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

Что же такое отложенные вычисления? В данном случае это не концепция языков программирования и в нашем случае никоим образом не связанно с компиляцией на лету. Термином “отложенные вычисления” я буду называть такие вычисления, выполнение которых можно отложить на некоторое время. Данный метод очень похож на методы многопоточного программирования.

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

  1. Инициализация
  2. Считывание состояния устройств управления
  3. Обновление состояния объектов
  4. Вывод информации на экран
  5. Вернуться к п.2

В данном алгоритме представлен цикл простой программы. Как можно догадаться в основном процессорное время будет тратится на обновление состояния объектов и вывод информации на экран и в случае, если программа будет вынуждена выполнять сложные и длительные алгоритмы при обновлении состояния своих объектов, то меньше времени будет отводится на вывод информации на экран (грубо говоря будет снижаться частота кадров). Метод отложенных вычислений позволяет уменьшить количество времени, которое процессор тратит на обновление своего состояния.

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

Проблема 1: в игре время от времени должен выполняться ресурсоемкий алгоритм, который требует много процессорного времени. В это время наблюдаются задержки. В остальное время процессор “простаивает”. Такое может возникать при выполнении алгоритмов А* поиска пути, подгрузке данных “на лету” и т.п.

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

Проблема 2: в игре множество событий, которые возникают(или могут возникнуть) при инкрементации счетчика времени. Одновременная обработка всех событий может привести к временному замедлению работы программы.

В данном случае нужно иметь список всех событий и также выполнять не все сразу, а с интервалами. При частоте 20-60 шагов обновлений в секунду, игрок не заметит разницы произошло какое-то событие на 1-м шаге или 5-м, т.к. это вопрос нескольких долей секунды, но это позволит разгрузить процессор достаточно сильно, что бы увеличить частоту кадров. Как и в предыдущем случае, за прирост производительности приходится платить, и делает это опять же программист. Ему необходимо построить такую модель обработки событий при которой он сможет формировать списки событий (а может и приоритетные списки) и решить каким образом он будет нормировать выполнение событий на одном шаге обновления. Есть несколько способов:

  • обрабатывать относительное количество событий за шаг(например, 20% от общей массы списка, но не меньше 50)
  • считать общее время, которое тратится на обработку событий, и, при достижении его определенного значения, прекращать обработку и переходить к другим действиям. В данном случае необходимо понимать то, что подсчет времени выполнения конкретного события также занимает определенное время и вполне может затормозить работу программы.
У этой статьи есть продолжение – “ Применение отложенных вычислений в Ignite “.