关闭从 QThread 运行的 Pygame 停止响应

问题描述 投票:0回答:2

我正在运行 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()
python pygame pyqt pyqt5 qthread
2个回答
3
投票

不要混合框架。这些框架可能彼此交互不良或完全冲突。如果它适用于您的(操作系统)系统,并不意味着它也适用于另一个(操作系统)系统或其中一个框架的不同版本。混合框架总是意味着某种未定义的行为。
如果您使用 Qt,那么我建议也使用 Qt 开发游戏(请参阅基于 Qt 的游戏)。


0
投票
  1. Pygame 不是线程安全的,因此除了数学和 pygame 中的各种其他类型的线程处理之外,它实际上不可能做任何事情。同样适用于 PyQt5,尽管有解决方法。

  2. 我找到了一种在 pyqt5 图像中嵌入和渲染 pygame 应用程序的方法。本质上,它让一个 pygame 程序在循环中产生屏幕,然后包含循环的这个函数在

    QTimer()
    内以 0 延迟运行。从 pygame 循环生成的屏幕变成图像,然后在
    QImage
    小部件上绘制。如果您想了解更多有关我的方法的细节,请参阅我创建的 github 存储库,它通过流程图更好地解释了它。查看此文件夹内部并运行
    preview_widget_test.py
    ,希望其中包含您正在寻找的内容。

  3. 如果您找到更好的方法(包括我的方法),请给予认可或让我知道。

© www.soinside.com 2019 - 2024. All rights reserved.