Найти в Дзене
Сделай игру

Проблематика: скорость игры

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

В старых аркадных автоматах, да и компьютерах, всё было предельно просто: процессор "выдавал" некоторую скорость вычисления, в результате чего персонажи игры двигались по экрану с определённой скорость. Например Space Invaders, которые я сейчас пытаюсь воспроизвести в качестве тренировки, работали на процессоре 8086, что приводило к забавному "глюку": как только пришельцев на экране становилось меньше, скорость обработки данных возрастала и скорость пришельцев увеличивалась.

По моим расчётам, текущая версия игры должна выполнить примерно 600 перемещений пришельцев, чтобы они приземлились (при условии, что платформа по ним не стреляет). При частоте обновления 60 кадров в секунду - игра продлится примерно 10 секунд, что гарантированное не позволит игроку вообще понять, что же делать: всё пролетит стремительно.

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

В случае с игрой Space Invaders я пошёл по самому простому пути: разделил экран на знакоместа и двигал спрайты по ним. Проще говоря, я превратил экран в матрицу X на Y элементов, и двигал не элементы по экрану, а просто менял их позиции в матрице. Всё шло хорошо ровно до того момента, пока не стало ясно, что игру надо притормозить.

По правде говоря, мне это было ясно изначально и я пошёл вот по какому пути: назначил для каждого объекта скорость в тактах: всего за 1 секунду выполняется 8 тактов и объекты выполняют движение каждое определённое число тактов. Например, пули и ракеты - 1 движение за 1 такт; ракетная платформа - 1 движение раз в 2 такта. Пришельцы - 1 движение раз в 8 тактов (и по мере уменьшения их числа скорость возрастала сперва до 1 раз в 4 такта, в потом до 1 раза в 2 такта).

А потом добавилось управление (я уже писал про него ранее). Всё бы ничего, но 8 тактов на секунду - это 125 милисекунд на такт. Вроде немного, однако, если нажать клавишу и сразу отпустить - движения не произойдёт. Более того, появляется некоторая задержка начала движения: дело в том, что платформа движется раз в 2 такта, то есть 1 раз в 250 милисекунд. Стало быть, при нажатии кнопки в самом пессимистическом случае проходят эти самые 250 милисекунд, прежде чем платформа начнёт двигаться. А это много. 100 милисекунд можно не заметить или не обратить на такую задержку внимание, а вот более 200 - уже заметно.

Я думал про увеличения количества тактов (до 16 или до 32), однако это не приводило к решению проблемы в целом: для сохранения такой же скорости движения надо было двигать элементы не на фиксированную ячейку за указанную единицу времени, а каждый кадр двигать на небольшое значение. То есть обеспечивать скорость не сдвигом номера в матрице, а сдвигом координат на некоторую дельту, которая для каждого типа объектов своя.

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

Вторым моментом, который необходимо учитывать - это предельная скорость обновления кадров. Я делал расчёт на 60 кадров в секунду, однако, есть немало вариантов, когда количество кадров снижается. Например, я делал эмулятор роста плесени. Это была довольно ресурсоёмкая задача и она выдавала всего 4 кадра в секунду. Безусловно, данный показатель можно было увеличить, однако не в этом суть: количество кадров может меняться и привязываться к этому значению не следует (тем более что оно может измениться и в большую сторону).

Что же делать? Тут, думаю, следует пойти опытным путём: сперва примерно понять количество кадров в секунду, потом вывести коэффициент. Если количество кадров меньше 60 (беру это значение за отправное), то увеличивать скорость движения элементов, если больше - то уменьшать.

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

Итак, выводы:

  1. Низкая отзывчивость приводит к тому, что пользователь может не сообразить, что управление работает: этого надо избегать;
  2. Опираться на скорость процессора как на мерило скорости игры - нельзя;
  3. Использовать матричные знакоместа для управления процессом игры можно, но лишь при условии, что это не повлияет на управляемость (например, маджонг или шашки);
  4. Если требуется хорошая отзывчивость игры, лучше устанавливать скорость смещения и двигать элементы на указанное количество пикселей (с заданной скоростью) через рассчитанный интервал времени;
  5. Скорость движения элементов должна быть ограничена минимальной и максимальной планкой во избежания рассинхронизации взаимодействия объектов либо же должен быть предусмотрен механизм взаимодействия объектов.

#makethegame #сделайигру