Pygame: display.update () не обновляется до истечения времени задержки - PullRequest
0 голосов
/ 07 мая 2018

Я использую Pygame time.Clock, чтобы запустить мою игру с более низким FPS, и я заметил, что мой ввод, казалось, занял один дополнительный кадр, чтобы вступить в силу. Я сделал некоторую отладку и понял, что это не проблема с pygame.event.get(), а скорее с pygame.display.update(). Я написал простую программу, чтобы продемонстрировать проблему: (Объяснение программы ниже фрагмента кода)

import pygame, sys
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
colour = 1
key_press = False

while True:
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN:
            screen.fill((0,255,0))
            key_press = True
            print("A key was pressed.")

    if not key_press:
        screen.fill((colour*255, colour*255, colour*255))
        colour = not colour
    else:
        key_press = False

    pygame.display.update()
    clock.tick(0.5)

Программа мигает экраном между черным и белым каждые две секунды, и всякий раз, когда нажимается какая-либо клавиша, экран меняется на зеленый, и на консоль выводится "A key was pressed". Однако, когда я запускаю его, текст печатается в правильное время, но экран не меняется на зеленый до следующего кадра. Это заставляет меня поверить, что pygame.display.update() не обновляет экран при вызове функции.

Кажется, проблема в задержке сразу после вызова pygame.display.update(). Если вы измените FPS часов, проблема все еще сохраняется. Это также происходит, если вы задерживаетесь с time.wait() или pygame.time.delay() вместо Clock.tick().

Еще одна интересная вещь, которую я заметил, это то, что если вы измените порядок последних двух строк кода в моем примере (pygame.display.update() и clock.tick(0.5)), вы можете ожидать, что экран изменится два тактовых циклов после нажатия клавиши вместо одной. Однако, если я сделаю это, то получу тот же эффект, что и в другом порядке.

Я не уверен, что это ошибка или здесь происходит что-то неуловимое, что я только что пропустил. Я использую Python 3.6.2 и использую Pygame v1.9.3 на macOS. Буду очень признателен за любую помощь!

Ответы [ 3 ]

0 голосов
/ 09 мая 2018

pygame.time.Clock.tick источник вызовов SDL_Delay, который позволяет программе спать в течение определенного времени.

Передавая 0,5 в качестве частоты кадров на clock.tick, вы говорите Pygame замедляться, чтобы обрабатывать только половину кадра в секунду. Это фактически означает, что игра будет обновляться только каждые две секунды, и она будет не отвечать на запросы в течение остального времени.

Если вы хотите реализовать таймер в pygame, используйте одно из решений здесь (pygame.time.get_ticks, set_timer или используйте дельта-время).

0 голосов
/ 25 июля 2019

Мне удалось исправить этот сбой в одной программе, вызвав pygame.event.pump () (который не очищает очередь событий, поэтому обработка событий не теряется) между вызовом pygame.display.update () и Clock.tick (FPS) вызов. По сути, мой основной игровой цикл закончился:

pygame.display.update()
pygame.event.pump()
clock_object.tick(FPS_CONSTANT)
0 голосов
/ 08 мая 2018

Я нашел способ устранить задержку в один кадр, которую я испытывал, хотя я до сих пор не могу объяснить, почему pygame.display.update() ожидает задержки по времени, чтобы обновить экран. Я решил опубликовать свое решение здесь на тот случай, если у кого-то возникнет такая же проблема.

Я заметил, что дисплей будет обновляться после запуска pygame.event.get(), поэтому я настроил свой цикл на проверку событий с более высокой частотой кадров. Я все еще хочу запустить свою игровую логику и обновить экран на более низкой частоте, поэтому я просто считаю, сколько раз цикл был выполнен. Обратите внимание на переменные frequency, FPS и skip_frames в моем новом примере ниже:

import pygame, sys
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()
colour = 1
key_press = False
frequency = 0.5 # How often the game logic is run
FPS = 30 # How often the user input is checked
skip_frames = FPS/frequency
count_frames = 0

while True:
    # *** Check for user input every loop ***
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN:
            key_press = True

    # *** Only run game logic at given frequency ***
    if count_frames >= skip_frames:
        count_frames -= skip_frames

        if key_press:
            screen.fill((0,255,0))
            print("A key was pressed.")
            key_press = False
        else:
            screen.fill((colour*255, colour*255, colour*255))
            colour = not colour

        pygame.display.update()

    count_frames += 1
    clock.tick(FPS)

Это немного обходной путь, но он дает результат, который я искал. Экран будет мигать с заданной частотой, и он станет зеленым при следующей вспышке после нажатия любой клавиши. Если кто-нибудь сможет выяснить, почему pygame.display.update() ожидает задержки по времени, чтобы фактически обновить экран, мне было бы очень интересно узнать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...