Использование простоя в пошаговых (RPG) играх для обновления

9

Если вы возьмете какую-нибудь пошаговую RPG-игру, будут большие периоды времени, когда ничего не происходит, потому что игра переходит в ожидание 'wait_for_player_input'. Естественно, разумно использовать это время для обновления вещей.

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

loop:  
if not check_something_pressed:  
    update_a_very_small_amount  
else  
  keep going

Но если мы скажем, что a_very_small_amount обновляет только один объект в каждом цикле, обновление будет очень медленным.

Как бы вы пошли об этом, желательно в одной теме?

РЕДАКТИРОВАТЬ: Я пометил этот независимый от языка, как это кажется разумным, хотя что-нибудь более специфичное для Python было бы здорово. ;-)

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

Коммунистическая утка
источник

Ответы:

7

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

Допустим, вы выбрали 60 FPS для своей игры. Таким образом, у вас остается 16,667 мс для выполнения всей работы, необходимой для каждого кадра. В начале игры получите текущее время, используя таймер с самым высоким разрешением, добавьте 16,667 мс и сохраните его где-нибудь. Я думаю, что функция в Python - это time (), хотя прошло уже много времени с тех пор, как я работал на языке. После завершения обработки введите цикл, который сравнивает текущее время с временем, которое вы записали. Если текущее время меньше времени окончания кадра, update_a_very_small_amount. Я бы не стал сильно беспокоиться о том, что обработка проходит после конца фрейма, поскольку ваше небольшое обновление должно быть быстрым для обработки. Это будет лишь небольшая задержка начала следующего кадра, и у вас будет достаточно времени для его обработки.

После того как кадр завершил обработку, добавьте 16,667 мс ко времени, которое было сохранено для конца последнего кадра, чтобы выяснить, где должен быть конец следующего кадра. Если вы используете текущее время + 16,667 мс, и обработка завершается, конец следующего кадра будет вытеснен на то же время, что и последний кадр.

Re: Второй Править

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

Джоэл Бейкер
источник
2

В частности, для Python вы можете попробовать использовать Coroutines для выполнения нескольких вызовов обновлений.

... сопрограммы - это программные компоненты, которые обобщают подпрограммы, позволяя нескольким точкам входа приостанавливать и возобновлять выполнение в определенных местах ...

PEP-0342 подробно описывает реализацию сопрограммы в Python.

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

Дэвид Янг
источник
1

Да, это возможно. В вашей игре будет какой-то основной игровой цикл. Что-то вроде этого:

while(gameRunning)
{
  checkUserInput()
  updateGame()
  renderGame()
}

В updateGame вы можете перебирать свои игровые объекты и обновлять их «немного». Если вы делаете какой-либо тяжелый расчет в этом методе, игра просто зависнет. Таким образом, вам нужен способ разделить эти вычисления, чтобы выполнить несколько итераций игрового цикла.

Как их разделить, зависит от того, какую игру вы строите. Предположим, у вас есть процедура поиска пути, которая использует A * для вычисления пути через лабиринт. Вам нужно будет остановить алгоритм через определенное время или после фиксированного количества итераций, сохранить рассчитанный путь и вернуть управление обратно в игровой цикл. Поиск пути будет продолжен при следующем вызове updateGame. Вы даже можете перемещать персонажа по частичному пути, пока он еще рассчитывается.

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

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

Стивен
источник
1

Насколько я понимаю ваш вопрос, вы спрашиваете о совместной многозадачности.

Базовая инфраструктура будет представлять собой список указателей на функции, все они будут вызываться циклически (если не требуется более сложная расстановка приоритетов), и все эти функции будут выполнять «небольшую работу», достаточно маленькую, чтобы игра не вызывала стать вялым. Я делал это в DOS, пока потоки не были горячими, а также на мобильных устройствах, которые не поддерживали многопоточность.

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

Лучшее решение, на мой взгляд, состоит в том, чтобы просто выйти из режима сна и позволить управлению питанием компьютера делать свою работу. Пользователям ноутбуков вам понравится больше.

Яри ​​Комппа
источник