gpt4 book ai didi

python-3.x - pygame多线程,程序崩溃

转载 作者:行者123 更新时间:2023-12-03 21:19:24 26 4
gpt4 key购买 nike

大家好,在此先感谢您的帮助。我刚刚发现了 pygame(一个 python 库),我想用它玩一下,但我遇到了一个问题。我尝试在我的代码中使用线程,但每次启动时程序都会崩溃。

我已经隔离了问题,并且我知道是 thread_1 导致了崩溃,因为当我将其注释掉时,一切又恢复正常了。我尝试更改thread_1 函数的代码,但它仍然崩溃。我很确定导致崩溃的不是函数 animateTitle 的内容,而是我使用线程的方式。

import pygame

from pygame.locals import *

from threading import Thread


def encadre(screen):
pygame.draw.line(screen, (250, 250, 250), (230, 140), (520, 140), 3)
pygame.draw.line(screen, (250, 250, 250), (230, 190), (520, 190), 3)
pygame.draw.line(screen, (250, 250, 250), (230, 140), (230, 190), 3)
pygame.draw.line(screen, (250, 250, 250), (520, 140), (520, 190), 3)


def initRoad(screen):
pygame.draw.line(screen, (250, 250, 250), (30, 0), (30, 500))
pygame.draw.line(screen, (250, 250, 250), (100, 0), (100, 500))
pygame.draw.line(screen, (250, 250, 250), (650, 0), (650, 500))
pygame.draw.line(screen, (250, 250, 250), (720, 0), (720, 500))
drawLines(screen)


def drawLines(screen):
i = 0
while i <= 49:
pygame.draw.line(screen, (250, 250, 250), (65, i * 10), (65, (i + 1) * 10))
pygame.draw.line(screen, (250, 250, 250), (685, i * 10), (685, (i + 1) * 10))
i = i + 3


def initText(screen, text1):
text1pos = text1.get_rect()
text1pos.x = 235
text1pos.y = 150
screen.blit(text1, text1pos)

font1 = pygame.font.Font(None, 30)
text1 = font1.render("PLAY", 1, (10, 10, 10))
text1pos = text1.get_rect()
text1pos.x = 210
text1pos.y = 310
screen.blit(text1, text1pos)

font1 = pygame.font.Font(None, 30)
text1 = font1.render("QUIT", 1, (10, 10, 10))
text1pos = text1.get_rect()
text1pos.x = 490
text1pos.y = 310
screen.blit(text1, text1pos)


def animateRoad(screen): # not done
pygame.draw.line(screen, (130, 130, 130), (65, 0), (65, 500))
pygame.draw.line(screen, (130, 130, 130), (685, 0), (685, 500))


def animateTitle(screen, text1):
text1pos = text1.get_rect()
while True:
pygame.draw.rect(screen, (130, 130, 130), (235, 150, 283, 35))
pygame.display.flip()
pygame.time.wait(500)
text1pos.x = 235
text1pos.y = 150
screen.blit(text1, text1pos)
pygame.display.flip()
pygame.time.wait(1000)


def loop(surface1, surface2):
while True:
for event in pygame.event.get():

if event.type == QUIT:
return

if event.type == pygame.MOUSEBUTTONDOWN:
if surface1.topleft[0] <= pygame.mouse.get_pos()[0] <= surface1.topright[0]:
if surface1.topleft[1] <= pygame.mouse.get_pos()[1] <= surface1.bottomleft[1]:
print('play')

if surface2.topleft[0] <= pygame.mouse.get_pos()[0] <= surface2.topright[0]:
if surface2.topleft[1] <= pygame.mouse.get_pos()[1] <= surface2.bottomleft[1]:
return

pygame.display.flip()
pygame.time.wait(10)


def main():
pygame.init()
screen = pygame.display.set_mode((750, 500))
pygame.display.set_caption('Infinite circle run')

background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((130, 130, 130))
screen.blit(background, (0, 0))

encadre(screen)
initRoad(screen)

surface1 = pygame.Rect(193, 290, 85, 50)
button1 = pygame.draw.rect(screen, (0, 0, 240), surface1)
surface2 = pygame.Rect(472, 290, 85, 50)
button2 = pygame.draw.rect(screen, (240, 0, 0), surface2)

font1 = pygame.font.Font(None, 50)
text1 = font1.render("Infinite circle run", 1, (0, 240, 0))
initText(screen, text1)

pygame.display.flip()

thread_1 = Thread(target=animateTitle(screen, text1), daemon=True)
thread_2 = Thread(target=loop(surface1, surface2))
# thread_3 = Thread(target=animateRoad(screen))

thread_1.start()
thread_2.start()
# thread_3.start()


if __name__ == '__main__':
main()

最佳答案

线程会导致许多问题,一般的经验法则是在不必要时避免它们。它们使您的程序具有不确定性、更难调试、更难测试、更难维护并且速度更慢(大多数情况下)。在您的程序中,没有理由使用线程。相反,你应该按顺序做事。 Pygame 会在必要时隐式创建线程(例如在处理 pygame.mixer 时)

为什么它不起作用,是因为 pygame 期望所有事件处理都发生 in the thread that set the video mode (pygame 使用的是 SDL2,因此该链接)。您不能在另一个线程中处理它们,并且由于您没有(正确)处理它们,操作系统会认为您的程序已崩溃。


我举了一个例子来展示制作动画的一种方法。这个概念是你告诉 pygame 在一定时间后,你想要发布一个事件。当该事件出现在您的事件循环中时,您将执行某些操作。

在您的例子中,您告诉 pygame 在 500 毫秒后发布 DRAW_TEXT_EVENT。当此事件出现在您的事件循环中时,您首先告诉 pygame 不要再发布 DRAW_TEXT_EVENT,而是在 1000 毫秒后发布 CLEAR_TEXT_EVENT。然后绘制文本。

1000 毫秒后,CLEAR_TEXT_EVENT 将出现在您的事件循环中。现在你基本上做同样的事情,但禁用 CLEAR_TEXT_EVENT 并告诉 pygame 在 500 毫秒后发布 DRAW_TEXT_EVENT

我没有对您的代码做太多改动。我在顶部为事件添加了 2 个定义。我已经删除了您的函数 loopanimateTitle,并将它们放入游戏循环中。最后,我在 main 函数中添加了游戏循环。

import pygame
from pygame.locals import *

# Events that we're going to post.
DRAW_TEXT_EVENT = pygame.USEREVENT + 1
CLEAR_TEXT_EVENT = pygame.USEREVENT + 2


def encadre(screen):
pygame.draw.line(screen, (250, 250, 250), (230, 140), (520, 140), 3)
pygame.draw.line(screen, (250, 250, 250), (230, 190), (520, 190), 3)
pygame.draw.line(screen, (250, 250, 250), (230, 140), (230, 190), 3)
pygame.draw.line(screen, (250, 250, 250), (520, 140), (520, 190), 3)


def initRoad(screen):
pygame.draw.line(screen, (250, 250, 250), (30, 0), (30, 500))
pygame.draw.line(screen, (250, 250, 250), (100, 0), (100, 500))
pygame.draw.line(screen, (250, 250, 250), (650, 0), (650, 500))
pygame.draw.line(screen, (250, 250, 250), (720, 0), (720, 500))
drawLines(screen)


def drawLines(screen):
i = 0
while i <= 49:
pygame.draw.line(screen, (250, 250, 250), (65, i * 10), (65, (i + 1) * 10))
pygame.draw.line(screen, (250, 250, 250), (685, i * 10), (685, (i + 1) * 10))
i = i + 3


def initText(screen, text1):
text1pos = text1.get_rect()
text1pos.x = 235
text1pos.y = 150
screen.blit(text1, text1pos)

font1 = pygame.font.Font(None, 30)
text1 = font1.render("PLAY", 1, (10, 10, 10))
text1pos = text1.get_rect()
text1pos.x = 210
text1pos.y = 310
screen.blit(text1, text1pos)

font1 = pygame.font.Font(None, 30)
text1 = font1.render("QUIT", 1, (10, 10, 10))
text1pos = text1.get_rect()
text1pos.x = 490
text1pos.y = 310
screen.blit(text1, text1pos)


def animateRoad(screen): # not done
pygame.draw.line(screen, (130, 130, 130), (65, 0), (65, 500))
pygame.draw.line(screen, (130, 130, 130), (685, 0), (685, 500))



def main():
pygame.init()
screen = pygame.display.set_mode((750, 500))
pygame.display.set_caption('Infinite circle run')

background = pygame.Surface(screen.get_size())
background = background.convert()
background.fill((130, 130, 130))
screen.blit(background, (0, 0))

encadre(screen)
initRoad(screen)

surface1 = pygame.Rect(193, 290, 85, 50)
button1 = pygame.draw.rect(screen, (0, 0, 240), surface1)
surface2 = pygame.Rect(472, 290, 85, 50)
button2 = pygame.draw.rect(screen, (240, 0, 0), surface2)

font1 = pygame.font.Font(None, 50)
text1 = font1.render("Infinite circle run", 1, (0, 240, 0))
initText(screen, text1)

pygame.display.flip()

pygame.time.set_timer(DRAW_TEXT_EVENT, 500)

text1pos = text1.get_rect()

# GAME LOOP
while True:

for event in pygame.event.get():
if event.type == QUIT:
return
elif event.type == pygame.MOUSEBUTTONDOWN:
if surface1.topleft[0] <= pygame.mouse.get_pos()[0] <= surface1.topright[0]:
if surface1.topleft[1] <= pygame.mouse.get_pos()[1] <= surface1.bottomleft[1]:
print('play')
elif surface2.topleft[0] <= pygame.mouse.get_pos()[0] <= surface2.topright[0]:
if surface2.topleft[1] <= pygame.mouse.get_pos()[1] <= surface2.bottomleft[1]:
return

elif event.type == DRAW_TEXT_EVENT:
pygame.draw.rect(screen, (130, 130, 130), (235, 150, 283, 35))
pygame.time.set_timer(DRAW_TEXT_EVENT, 0) # Disable the event.
pygame.time.set_timer(CLEAR_TEXT_EVENT, 1000) # Post event after 1000ms.
elif event.type == CLEAR_TEXT_EVENT:
text1pos.x = 235
text1pos.y = 150
screen.blit(text1, text1pos)
pygame.time.set_timer(CLEAR_TEXT_EVENT, 0) # Disable the event.
pygame.time.set_timer(DRAW_TEXT_EVENT, 500) # Post event after 500ms.

# Only call once each frame!
pygame.display.flip()


if __name__ == '__main__':
main()

关于python-3.x - pygame多线程,程序崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54470051/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com