【问题标题】:Why is my pause system not working? (Pygame)为什么我的暂停系统不起作用? (游戏)
【发布时间】:2013-09-23 20:15:19
【问题描述】:

这是我的 check_for_pause() 函数:

#Check if the user is trying to pause the game
def check_for_pause():
   keys=pygame.key.get_pressed() #Get status of all keys
   if keys[K_SPACE]: #The space bar is held down
       global paused #Make global so it can be edited
       if paused==True: #It was paused, so unpause it
           paused=False
       elif paused==False: #It was playing, so pause it
           paused=True

        #Don't let the main loop continue until the space bar has been released again, otherwise the variable will flicker between True and False where the loop runs so fast!
        space_bar_pressed=keys[K_SPACE]
        while space_bar_pressed: #Repeat this loop until space_bar_pressed is False
           keys=pygame.key.get_pressed()
           if not keys[K_SPACE]: #Space bar has been released so set space_bar_pressed to False
              space_bar_pressed=False

但是,每当我尝试暂停它时,这都会使我的程序变得无响应!基本上,我希望变量“暂停”为真或假。按下空格键时,它应该更改为当前不是的那个。因为我在另一个永无止境的循环中使用了 check_for_pause(),所以我需要使它仅在释放空格键时才停止执行,否则如果用户按住空格键超过一秒钟,它将不断在真假之间切换。

任何想法为什么我的程序在运行时变得无响应?我知道这与等待空格键被释放的位有关,因为当我删除那段代码时,我的程序运行良好(但显然暂停功能不起作用)。

【问题讨论】:

  • 您不使用事件队列是否有原因?当一个键被按下时,该键的 single 事件被发送到队列中,释放时也是如此。使用队列将确保您的暂停开关只触发一次。
  • “但是,每当我尝试暂停它时,这都会使我的程序变得无响应!”嗯,当然可以。您正在运行一个循环,该循环在您释放空格键之前不会返回,因此程序可能无法响应其他任何内容,因为它仍在运行循环中的代码。
  • (这正是 为什么您应该为几乎所有 GUI 应用程序使用事件循环设计。)
  • 一个问题是您正在检查键是否被按住。您想要切换 KEYDOWN 事件。否则,您每秒会进行多次切换。

标签: python pygame


【解决方案1】:

你有一个可能看起来像这样的主循环......

while True:
    check_for_pause()
    # Update the game
    # Draw the game

当您检查暂停并按下空格键时,暂停设置为 True。然后,你就有了这个循环......

space_bar_pressed=keys[K_SPACE]
while space_bar_pressed: #Repeat this loop until space_bar_pressed is False
   keys=pygame.key.get_pressed()
   if not keys[K_SPACE]: #Space bar has been released so set space_bar_pressed to False
      space_bar_pressed=False

这个循环的问题是你假设 pygame.key.get_pressed() 将继续返回最新信息。但是,查看pygame source code,它似乎使用了 SDL_GetKeyState,这是其文档的一部分..

Note: Use SDL_PumpEvents to update the state array.

换句话说,如果你没有额外调用类似pygame.event.pump() 的东西,重复调用 pygame.key.get_pressed() 不会给你更新的键状态,它实际上用新的键状态更新了 pygame。因此,您可以通过将泵功能引入循环来快速解决此问题,因为目前它只是永远运行。

话虽这么说:不要这样做。如果您这样做,您的游戏在暂停时将无法执行任何操作:这包括显示“暂停”屏幕、继续在后台播放音乐等。您想要做的是跟踪是否游戏已暂停,如果是,请更改游戏的更新方式。

在您更新内容的游戏部分,某些项目只有在游戏暂停时才会出现。比如……

paused = False
while True:
    # This function should just return True or False, not have a loop inside of it.
    paused = check_for_paused()

    if not paused:
        # This function moves your enemies, do physics, etc.
        update_game()

    draw_game()

在这种情况下,主循环仍然会发生,游戏会继续绘制,输入会继续处理。但是敌人和玩家不会移动,所以游戏可以说是“暂停”了。

最后,还有一个事实是您依赖于 get_key_pressed(),而您可能不想这样做。请参阅 this other similar answer 我已经给出了您应该使用事件队列的原因。

【讨论】:

  • 很好的解释。但实际上,他应该编写一个循环遍历pygame.event.get() 的主循环,而不是尽可能快地循环并轮询事件(如the tutorial 中所述)。
  • 非常有帮助的答案。非常感谢!
【解决方案2】:

即使游戏暂停,您也不应该停止在游戏中运行游戏循环。暂停通常也是通过事件来处理的。例如看这段代码:

import pygame, sys
from pygame.locals import *
pygame.init()
pygame.display.set_mode((400,400))

paused = False # global

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN:
            if event.key == K_SPACE:
                paused = not paused

    if paused:
        continue # skip this iteration if paused

    # add your game code here
    print 'game code running'

在上面的代码中,我每次按空格键时都会暂停。如果您只想在按住空格键时暂停,请执行以下操作:

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type in (KEYDOWN, KEYUP): # checks membership in tuple
            if event.key == K_SPACE:
                paused = not paused

    if paused:
        continue # skip this iteration if paused

    # add your game code here
    print 'game code running'

作为一般说明,您应该始终处理来自事件队列的事件,否则 Pygame 将只会哭泣和抱怨并且什么都不做(无响应)。因此,即使您暂停了游戏,也永远不要停止游戏循环。

编辑:或者,正如 abarnert 在 cmets 中指出的那样,您可以使用相等比较来确保您永远不会在 KEYDOWN 和 KEYUP 事件之间发生冲突:

paused = event.type == KEYDOWN

这样您就不会遇到“同步问题”,即每当您实际释放空格键时,代码会意外地将 paused 设置为 True。如果连续发生 2 个 KEYDOWN 事件或连续发生 2 个 KEYUP 事件(而不是像 KEYDOWN、KEYUP、KEYDOWN、KEYUP 等平滑交替序列),则可能会发生这种情况。最好不要假设所有事件队列都提供 100% 准确的事件。

【讨论】:

  • 我认为写paused = event.type == KEYDOWN 或类似的东西比在第二个版本中切换更清楚。另外,它避免了您可能会以某种方式“不同步”并最终暂停的可能性,除非空格键被按下,而不是当它被按住时。但除此之外,这是一个很好的答案。
  • @abarnert 添加了关于您提到的同步问题的注释。 :)
猜你喜欢
  • 2016-11-04
  • 1970-01-01
  • 2010-11-09
  • 1970-01-01
  • 2016-01-09
  • 1970-01-01
  • 2021-08-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多