Лучший способ обрабатывать синхронизированные события в PyGame - PullRequest
2 голосов
/ 26 мая 2010

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

pygame.time.set_timer(USEREVENT+1, 300)

Это, конечно, будет добавлять событие PyGame в очередь каждые 300 миллисекунд. В основном цикле я могу проверить это событие и опустить блок, когда оно произойдет. Проблема с этим подходом состоит в том, что игрок может легко заполнить очередь событиями, генерируемыми клавиатурой. Я заметил, что игрок может по существу держать блок на одной и той же высоте бесконечно, просто быстро нажимая стрелку вверх, которая переворачивает его. Кажется, не имеет значения, что тестирование кода для события таймера оценивается перед тестом для событий клавиатуры. Почему-то клавиатура всегда получает более высокий приоритет, чем таймер. Есть идеи, как этого избежать?

А если это неизбежная особенность pygame.time, что может быть лучше для обработки событий по времени?

  • Проверить истекшее время на каждой итерации цикла и опережать блоки, если оно больше определенного значения?
  • Использовать sched или что-то подобное, запущенное в отдельном потоке и возвращающее сигнал через какой-то общий ресурс?

Есть идеи?

Ответы [ 2 ]

3 голосов
/ 26 мая 2010

Вот как работает типичный игровой цикл:

repeat forever:
    read all pending events
    if current time > last frame + frame time:
        last frame = last frame + frame time
        update game
    redraw screen

Таймер, который должен срабатывать каждые 300 мс, но не работает, если пользователь затопляет игру событиями, может быть сломан таймер. Однако, если вы перерисовываете экран для каждого пользовательского события вместо перерисовки экрана после обработки всех ожидающих событий, проблема заключается в вашем коде.

Вот пример сломанной версии игрового цикла:

repeat forever:
    read the next pending event
    if current time > last frame + frame time:
        last frame = last frame + frame time
        update game
    redraw screen

Он сломан, потому что слишком часто пытается перерисовать экран. Если игрок нажмет две клавиши одновременно, они будут разделены на разные кадры, что не нужно.

Вышеуказанные циклы предполагают, что вы хотите рисовать на экране как можно чаще. Это очень часто, но вы можете рисовать на экране реже. Ваш метод использования событий должен быть в порядке, если вы перехватываете все ожидающие события перед перерисовкой экрана.

P.S. НЕ используйте несколько потоков для решения этой проблемы. Это вызвало бы огромный беспорядок.

0 голосов
/ 26 мая 2010

Одна поправка к ответу Дитриха Эппа - redraw screen должна фактически интерполировать или экстраполировать между двумя последующими игровыми состояниями. Это необходимо, чтобы обеспечить игрокам приятный опыт.

В случае интерполяции, в качестве коэффициента интерполяции вы используете долю времени, которая «остается» от обновления (потому что она меньше frame time), деленную на время кадра, чтобы получить результат в диапазоне [0..1].

Это также известно как канонический игровой цикл

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