为了账号安全,请及时绑定邮箱和手机立即绑定

Pygame 的线程问题

Pygame 的线程问题

陪伴而非守候 2021-08-11 19:41:44
我正在开发一个用于学习目的的小游戏。我为标题画面创建了一个简单的动画。由于代码中还有一个全屏功能,我想创建一个标题屏幕:显示动画当按键被激活时变成全屏在激活全屏之前的点继续动画为了做到这一点,我求助于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动画的代码是:TitleWhite = [255, 255, 255, 0]Black = BASE_BLACKTitleLetters = ("R", "O", "G", "U", "E", " ", "H", "U", "N", "T", "E", "R")Title = FontDictionary["TitleFont"][1].render("ROGUE HUNTER", False, TitleWhite)TextWidth = Title.get_width()TextHeight = Title.get_height()TitleXPosition = (WindowDimensions[0] - TextWidth) / 2TitleYPosition = (WindowDimensions[1] / 2) - (TextHeight / 2)for letter in TitleLetters:    if letter == " ":       TitleXPosition += CurrentLetterWidth    else:        while TitleWhite[3] < 100:            TitleWhite[3] += 1            CurrentLetter = FontDictionary["TitleFont"][1].render(letter, False, TitleWhite)            CurrentLetter.set_alpha(TitleWhite[3])            Window.blit(CurrentLetter, (TitleXPosition, TitleYPosition))            time.sleep(0.008)            try:                 pygame.display.update()            except Exception:                traceback.print_exception如果有人能帮助我解决这个问题,我将不胜感激。我快疯了。
查看完整描述

2 回答

?
慕姐8265434

TA贡献1813条经验 获得超2个赞

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


通常,您希望在游戏中使用某种状态来确定帧中应该发生什么。您可以在此处找到基于类的示例。


处理此问题的另一种方法与您的代码有点相似,是使用协程。


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


这是一个简单的hacky示例:


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()

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


在此处输入图片说明


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


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


查看完整回答
反对 回复 2021-08-11
  • 2 回答
  • 0 关注
  • 128 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号