Pygam的线程问题

2024-10-04 07:28:04 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在开发一个小游戏用于学习。我为标题屏幕创建了一个简单的动画。因为代码中还有一个全屏显示功能,所以我想创建一个标题屏幕:

  1. 显示动画
  2. 当按键被激活时变成全屏
  3. 在激活全屏之前继续动画

为了做到这一点,我求助于threading。然而,这是我第一次尝试多线程,我不知道我做错了什么。结果是一个未确定的错误。在

标题屏幕的代码如下:

try:
    GameAnimation = threading.Thread(target=GameTitleAnimation, (Window, WindowDimensions, FontDictionary, CurrentVersion))
    GameAnimation.start()
except:
    print "There was an error while loading the screen. Press one key to exit the program."
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            Quit()
        if event.type == pygame.KEYDOWN:
            if event.key == K_ESCAPE:
                Quit()
            elif event.key == K_f:
                Fullscreen(Window, WindowDimensions)
            else:
                return

动画的代码是:

^{pr2}$

如果有人能帮我,我会非常感激的。我快疯了。在


Tags: thekey代码event标题if屏幕动画
2条回答

没有理由在代码中使用线程。它只会让你的代码更难阅读,更难调试,更容易出错。在

通常你想在你的游戏中有一种状态,你用它来确定一个帧中应该发生什么。您可以找到一个基于类的示例here。在

另一种处理此问题的方法(与您的代码有点类似)是使用协同程序。在

查看动画代码,不要调用pygame.display.update(),而是将控件返回主循环。主循环将处理事件、帧限制和绘制,然后将控制权交还给协同程序(它跟踪自己的状态)。在

下面是一个简单的黑客示例:

import pygame
import pygame.freetype

pygame.init()
size = (640, 480)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()

def game_state(surf):
    rect = pygame.Rect(200, 200, 32, 32)
    while True:
        events = yield
        pressed = pygame.key.get_pressed()
        x = 1 if pressed[pygame.K_RIGHT] else -1 if pressed[pygame.K_LEFT] else 0
        rect.move_ip(x*5, 0)
        pygame.draw.rect(surf, pygame.Color('dodgerblue'), rect)
        yield

def title_state(surf):
    text = 'Awesome Game'
    colors = [[255, 255, 255, 20] for letter in text]
    font = pygame.freetype.SysFont(None, 22)
    font.origin = True
    while True:
        for color in colors:
            color[3] += 33
            if color[3] > 255: color[3] = 0
            x = 200
            for (letter, c) in zip(text, colors):
                bounds = font.get_rect(letter)
                font.render_to(surf, (x, 100), letter, c)
                x += bounds.width + 1

            font.render_to(surf, (180, 150), 'press [space] to start', pygame.Color('grey'))
            events = yield
            yield

def main():
    title = title_state(screen)
    game = game_state(screen)
    state = title

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
            if e.type == pygame.KEYDOWN:
                if e.key == pygame.K_ESCAPE:
                    return
                if e.key == pygame.K_SPACE:
                    state = game if state == title else title
                if e.key == pygame.K_f:
                    if screen.get_flags() & pygame.FULLSCREEN:
                        pygame.display.set_mode(size)
                    else:
                        pygame.display.set_mode(size, pygame.FULLSCREEN)

        screen.fill(pygame.Color('grey12'))
        next(state)
        state.send(events)
        pygame.display.update()
        clock.tick(60)

if __name__ == '__main__':
    main()

看看主循环是如何干净和简单的,所有的游戏状态都是在协同程序中处理的。代码的标题屏幕部分不关心是否全屏显示或如何切换到全屏,主循环不关心标题屏幕协同程序做什么。我们不需要穿线。在

enter image description here

实际上,它与我上面链接的基于类的示例没有什么不同,但是使用协同程序可以很容易地实现标题屏幕动画。在

基本上你有一个无止境的循环,你改变一些状态(比如字母的颜色),然后说“现在画这个!”只需调用yield。在

这是需要调试的大量代码。在

我不熟悉pygame或python线程,但在我看来,您需要包括一些调试行来确定在游戏动画线程期间发生错误的确切位置(如果它确实发生在那里)。在

类似这样的模式应该有助于确定问题的根源:

import logging

logging.info("start animation initialization")
...
logging.info("begin animation loop")
...
logging.info("end animation loop")

https://docs.python.org/2/howto/logging.html

相关问题 更多 >