我正在运行 PyQt5 制作的游戏库中的 pygame 蛇游戏。我正在使用 QThread 运行。在我关闭游戏之前它一直运行良好。每当我使用关闭按钮关闭游戏时,pygame 窗口和 GUI 都会停止响应。我该如何解决这个问题:
游戏库GUI:
from PyQt5 import QtCore, QtGui, QtWidgets
class Snake(QtCore.QThread):
def start_game(self):
import Games.sanke_game #Imports and starts the game
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(853, 476)
MainWindow.setIconSize(QtCore.QSize(64, 64))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.frame = QtWidgets.QFrame(self.centralwidget)
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.frame)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.label = QtWidgets.QLabel(self.frame)
self.label.setObjectName("label")
self.verticalLayout_2.addWidget(self.label)
self.singleContainer = QtWidgets.QWidget(self.frame)
self.singleContainer.setObjectName("singleContainer")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.singleContainer)
self.horizontalLayout.setObjectName("horizontalLayout")
self.snakeGame = QtWidgets.QPushButton(self.singleContainer)
self.snakeGame.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.snakeGame.setIconSize(QtCore.QSize(64, 64))
self.snakeGame.setObjectName("snakeGame")
self.horizontalLayout.addWidget(self.snakeGame)
self.guessGame = QtWidgets.QPushButton(self.singleContainer)
self.guessGame.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.guessGame.setIconSize(QtCore.QSize(64, 64))
self.guessGame.setObjectName("guessGame")
self.horizontalLayout.addWidget(self.guessGame)
self.targetGame = QtWidgets.QPushButton(self.singleContainer)
self.targetGame.setIconSize(QtCore.QSize(55, 55))
self.targetGame.setObjectName("targetGame")
self.horizontalLayout.addWidget(self.targetGame)
self.spaceGame = QtWidgets.QPushButton(self.singleContainer)
self.spaceGame.setIconSize(QtCore.QSize(55, 55))
self.spaceGame.setObjectName("spaceGame")
self.horizontalLayout.addWidget(self.spaceGame)
self.verticalLayout_2.addWidget(self.singleContainer, 0, QtCore.Qt.AlignLeft)
self.label_2 = QtWidgets.QLabel(self.frame)
self.label_2.setObjectName("label_2")
self.verticalLayout_2.addWidget(self.label_2)
self.multiContainer = QtWidgets.QWidget(self.frame)
self.multiContainer.setObjectName("multiContainer")
self.horizontalLayout_5 = QtWidgets.QHBoxLayout(self.multiContainer)
self.horizontalLayout_5.setObjectName("horizontalLayout_5")
self.verticalLayout_2.addWidget(self.multiContainer)
self.label_3 = QtWidgets.QLabel(self.frame)
self.label_3.setObjectName("label_3")
self.verticalLayout_2.addWidget(self.label_3)
self.computerContainer = QtWidgets.QWidget(self.frame)
self.computerContainer.setObjectName("computerContainer")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.computerContainer)
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.ticTacToeGame = QtWidgets.QPushButton(self.computerContainer)
self.ticTacToeGame.setIconSize(QtCore.QSize(55, 55))
self.ticTacToeGame.setObjectName("ticTacToeGame")
self.horizontalLayout_2.addWidget(self.ticTacToeGame)
self.verticalLayout_2.addWidget(self.computerContainer, 0, QtCore.Qt.AlignLeft)
self.verticalLayout.addWidget(self.frame)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
# Button clicking function
self.snakeGame.clicked.connect(lambda: self.game_choose("snake"))
self.targetGame.clicked.connect(lambda: self.game_choose("target"))
self.guessGame.clicked.connect(lambda: self.game_choose("guess"))
self.spaceGame.clicked.connect(lambda: self.game_choose("space"))
self.ticTacToeGame.clicked.connect(lambda: self.game_choose("tic-tac-toe"))
# Functions for starting the game (Only choose the snake as its the only game now)
def game_choose(self, choice):
if choice == "snake":
self.snake_worker = Snake()
self.snake_worker.start_game()
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Games"))
self.label.setText(_translate("MainWindow", "Single Player"))
self.snakeGame.setText(_translate("MainWindow", "Snake"))
self.guessGame.setText(_translate("MainWindow", "Guess"))
self.targetGame.setText(_translate("MainWindow", "Target"))
self.spaceGame.setText(_translate("MainWindow", "Space Invader"))
self.label_2.setText(_translate("MainWindow", "Multiplayer"))
self.label_3.setText(_translate("MainWindow", "VS Computer"))
self.ticTacToeGame.setText(_translate("MainWindow", "Tic-Tac-Toe"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
贪吃蛇游戏pygame文件(该游戏中的贪吃蛇苹果需要图像。因此请放置任何32x32图像以避免错误):
import pygame
import random
# initialize pygame
pygame.init()
# Colors
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
# Screen set & title
screen_width = 900
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("Snake")
# Object images
appleImg = pygame.image.load("Game_resources\\Snake\\apple.png") # Put somg random images to avoid error
"""Variables"""
fps = 60
# Snake
snakeX = 32
snakeY = 32
snake_size = 32
snakeX_velocity = 0
snakeY_velocity = 0
velocityX = False
velocityY = False
# Apple
appleX = random.randint(20, 848)
appleY = random.randint(20, 548)
# Score text
score_value = 0
font = pygame.font.Font('freesansbold.ttf', 20)
#Game Over
over_font = pygame.font.Font('freesansbold.ttf', 50)
game_over_var = False
# Snakes and lenth
snk_list = []
snk_lenth = 1
"""Functions"""
def game_over():
GameOver = over_font.render("GAME OVER", True, red)
screen.blit(GameOver, (screen_width/3, screen_height/2.5))
def score_show():
score = font.render("Score: " + str(score_value), True, black)
screen.blit(score, (5, 5))
def apple_location(x, y):
screen.blit(appleImg, (x, y))
def plot_snake(window, color, snk_list, snake_size):
for x, y in snk_list:
pygame.draw.rect(window, color, [x, y, snake_size, snake_size])
# Game running variable
running = True
clock = pygame.time.Clock()
# Loop
def gameloop():
global running
global screen
global snakeX_velocity
global snakeY_velocity
global velocityX
global velocityY
global snakeX
global snakeY
global appleX
global appleY
global score_value
global snk_lenth
global snk_list
global game_over_var
while running:
screen.fill(white)
if game_over_var == True:
screen.fill(white)
game_over()
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RETURN:
game_over_var = False
snakeX_velocity = 0
snakeY_velocity = 0
velocityX = False
velocityY = False
snakeX = 32
snakeY = 32
snk_list = []
snk_lenth = 1
score_value = 0
gameloop()
else:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_RIGHT:
if velocityX == False:
snakeX_velocity = 4
snakeY_velocity = 0
velocityX = True
velocityY = False
if event.key == pygame.K_LEFT:
if velocityX == False:
snakeX_velocity = -4
snakeY_velocity = 0
velocityX = True
velocityY = False
if event.key == pygame.K_UP:
if velocityY == False:
snakeX_velocity = 0
snakeY_velocity = -4
velocityX = False
velocityY = True
if event.key == pygame.K_DOWN:
if velocityY == False:
snakeX_velocity = 0
snakeY_velocity = 4
velocityX = False
velocityY = True
snakeX += snakeX_velocity
snakeY += snakeY_velocity
if abs(snakeX - appleX)<25 and abs(snakeY - appleY)<25:
score_value += 10
appleX = random.randint(20, 848)
appleY = random.randint(20, 548)
snk_lenth+=10
head = []
head.append(snakeX)
head.append(snakeY)
snk_list.append(head)
if len(snk_list)>snk_lenth:
del snk_list[0]
if snakeX >= 848 or snakeX <=20 or snakeY >=548 or snakeY <=20:
game_over_var = True
score_show()
apple_location(appleX, appleY)
plot_snake(screen, black, snk_list, snake_size)
clock.tick(fps)
pygame.display.update()
gameloop()
不要混合框架。这些框架可能彼此交互不良或完全冲突。如果它适用于您的(操作系统)系统,并不意味着它也适用于另一个(操作系统)系统或其中一个框架的不同版本。混合框架总是意味着某种未定义的行为。
如果您使用 Qt,那么我建议也使用 Qt 开发游戏(请参阅基于 Qt 的游戏)。
Pygame 不是线程安全的,因此除了数学和 pygame 中的各种其他类型的线程处理之外,它实际上不可能做任何事情。同样适用于 PyQt5,尽管有解决方法。
我找到了一种在 pyqt5 图像中嵌入和渲染 pygame 应用程序的方法。本质上,它让一个 pygame 程序在循环中产生屏幕,然后包含循环的这个函数在
QTimer()
内以 0 延迟运行。从 pygame 循环生成的屏幕变成图像,然后在 QImage
小部件上绘制。如果您想了解更多有关我的方法的细节,请参阅我创建的 github 存储库,它通过流程图更好地解释了它。查看此文件夹内部并运行 preview_widget_test.py
,希望其中包含您正在寻找的内容。
如果您找到更好的方法(包括我的方法),请给予认可或让我知道。