2013-09-23 4 views
0

Вот моя check_for_pause функция():Почему моя система паузы не работает? (Pygame)

#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 

однако это продолжает делать моя программа перестает отвечать на запросы, когда я пытаюсь сделать паузу! В принципе, я хочу, чтобы переменная «paused» была либо True, либо False. Когда нажимается пробел, он должен измениться в зависимости от того, в каком он сейчас нет. Поскольку я использую check_for_pause() в другом бесконечном цикле, мне нужно сделать так, чтобы функция прекращала выполнение только при освобождении пробела, иначе, если пользователь удерживает пробел более чем на долю секунды, он будет переключение между True и False.

Любые идеи, почему моя программа становится неактуальной, когда я запускаю это? Я знаю, что это связано с бит, который ждет, пока пробел не будет выпущен, потому что, когда я удаляю этот бит кода, моя программа работает нормально (но, очевидно, функция паузы не работает).

+1

Есть ли причина, по которой вы не используете очередь событий? Когда нажата клавиша, событие * single * для этого ключа отправляется в очередь, то же самое, когда он отпускается. Использование очереди будет гарантировать, что ваш переключатель паузы будет запущен только один раз. –

+0

«однако это продолжает заставлять мою программу не реагировать, когда я пытаюсь ее приостановить!» Ну, конечно. Вы запускаете цикл, который не возвращается, пока вы не отпустите пробел, поэтому программа не может реагировать ни на что другое, потому что она все еще работает с кодом в цикле. – abarnert

+0

(И это точно _why_ вы должны использовать дизайн цикла событий для почти любого графического приложения.) – abarnert

ответ

6

У вас есть основной цикл, который, вероятно, выглядит примерно так ...

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.key.get_pressed() не даст вам обновленный ключ если вы не вызываете дополнительно что-то вроде pygame.event.pump(), которое фактически обновляет 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 Я привел причины, по которым вы должны использовать очередь событий.

+0

Хорошее объяснение. Но на самом деле он должен написать основной цикл, который зацикливается на 'pygame.event.get()', а не на цикличность как можно быстрее и на опрос для событий (как объяснено в [учебнике] (http: //www.pygame. орг/документы/Tut/том/games2.html)). – abarnert

+0

Очень полезный ответ. Большое спасибо! – RedRocker227

3

Вы никогда не должны останавливать свою игру в игре, даже если она приостановлена. Также паузы обычно обрабатываются событиями. Например посмотрите на этот код:

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 просто плакать и ныть и ничего не делать (быть отвечать на запросы). Таким образом, никогда не переставайте вращаться в игровом цикле, даже если вы приостановили игру.

EDIT: В качестве альтернативы, в качестве abarnert отметил в комментариях вы можете сделать трюк с сравнениями равенства, чтобы гарантировать, что вы никогда не получите конфликты между KeyDown и KeyUp событиями:

paused = event.type == KEYDOWN 

Таким образом, вы не будете иметь «проблемы синхронизации», где код случайно устанавливает paused в True, когда вы фактически освобождаете пробел. Это может произойти, если 2 события KEYDOWN произойдут в строке или если 2 события KEYUP происходят в строке (вместо гладкой чередующейся последовательности, такой как KEYDOWN, KEYUP, KEYDOWN, KEYUP и т. Д.). Лучше не предполагать, что все очереди событий подают события, которые на 100 процентов точны.

+0

Я думаю, что яснее писать 'paused = event.type == KEYDOWN' или подобное, а не переключать во второй версии. Кроме того, это позволяет избежать возможности, что вы каким-то образом «не синхронизированы» и в конечном итоге приостановите работу, если пробел не поможет, а не когда он удерживается. Но в остальном это отличный ответ. – abarnert

+0

@abarnert добавил заметку о проблемах синхронизации, о которых вы упомянули. :) – Shashank

Смежные вопросы