Эту статью не стоит рассматривать как истину в последней инстанции, отнеситесь к ней, как к пище для размышления. Возможно, вам это никогда не пригодится, а может быть это именно то, что вы так долго искали.
Итак, речь пойдет об игровом движке Gamemaker, а точнее об одной лишь его переменной, которую по каким-то причинам в подавляющем большинстве уроков по Gamemaker даже не упоминают.
Откуда ноги растут
Самый простой способ перемещать объект по экрану в Gamemaker - задать его горизонтальную и вертикальную скорость, присвоив нужные нам значения переменным объекта hspeed и vspeed. Или задать скорость движения и направление переменными speed и direction. Объект будет двигаться с нужной нам скоростью в нужном направлении.
Казалось бы всё здорово, бери и пользуйся. Однако, а будет ли "нужная нам скорость" соответствовать нашим ожиданиям? Давайте выяснять.
Подвох вот в чем: переменные hspeed, vspeed, speed хранят скорость, выраженную в пикселах за один кадр. Известно, что стандартное значение FPS игры равно 60 и при желании изменяется в настройках проекта. Исходя из этого значения можно легко вычислить продолжительность кадра, она равна 0,016 сек. Это теоретически.
Написав простейший код, мы можем замерять время каждого кадра на практике. Для этого нам понадобится лишь одна внутренняя переменная delta_time, которая как раз и содержит время, прошедшее между началом предыдущего и началом текущего кадров. На моей машине это время колеблется от 0,014 сек. до почти 0,02 сек., а это 30%. На мой взгляд разница ощутимая. И это на пустом проекте, где в каждом кадре нет обработки огромного и, к тому же, разного количества событий, простых и сложных. Плюс к этому, на разных устройствах эта разница тоже будет разной. Понятно, что среднее значение не будет далеко уходить от эталонного 0,016, но в какие-то моменты мы можем не получить ожидаемой плавности игры.
К счастью, эта просто исправить.
Чтобы руки росли не оттуда, откуда ноги
Как уже было сказано, переменная delta_time содержит время, прошедшее между началом предыдущего и началом текущего кадров. В микроисекундах.
Отлично! Осталось лишь приучить себя измерять скорость в пикселях в секунду, переводить их в пиксели за кадр и в каждом кадре подставлять скорректированное относительно delta_time значение скорости движения нашего объекта.
Например, мы хотим, чтобы за секунду реального времени наш объект преодолевал расстояние 300 пикселей по горизонтали. Выглядеть это будет так:
var CerrentSpeed = 300;
var DT = delta_time / 1000000; // переводим микросекунды в секунды
hspeed = DT * CurrentSpeed;
Этот код должен выполняться в каждом кадре пока мы хотим, чтобы наш объект двигался.
Что-то вроде плюшки
Можно пойти дальше и провернуть такой трюк. Определим в скрипте глобальную переменную и функцию:
// Коэффициент ускорения времени
global.TimeScale = 1;
// Определение delta_time в зависимости от коэффициента ускорения времени
function GetDeltaTime (_TimeScale = global.TimeScale) {
return delta_time * _TimeScale;
}
Скорректируем наш предыдущий код:
var CerrentSpeed = 300;
var DT = GetDeltaTime() / 1000000; // переводим микросекунды в секунды
hspeed = DT * CurrentSpeed;
И теперь, если все объекты и персонажи в нашей игре будут перемещаться используя этот принцип, мы сможем замедлять, или ускорять ход игры изменением лишь одной глобальной переменной. Догадаетесь какой именно? Правильно, global.TimeScale.
А если захотим замедлить или ускорить кого-то одного, то при вычислении DT нужно передать в функцию GetDeltaTime() значение нужного нам коэффициента (GetDeltaTime(0.5) замедлит движение вдвое).
Наконец-то всё?
У этого метода, конечно, есть нюанс. Вычисление скорости мы должны проделывать на каждом шаге. А там еще деление на 1000000, а оно ого‑го как затратно (на самом деле нет). Готовы ли мы ради какой‑то плавности движения жертвовать производительностью?
Конечно, готовы! Мы же говорим о 2D иглульке, с нынешними мощностями у нас этой производительности как... Ну, сами придумайте окончание фразы.
Каждый сам решит использовать ли ему этот метод или нет. Если вы новичок, думаю вам будет по крайней мере полезно об этом знать. Если вы, в отличие от меня, программист и уже разработали миллион миллионов топовых игр, наверное, вы поржёте и скажете: «Какие, к чёрту, погрешности? И так всё работает, зачем усложнять?» Поржите, но аргументировано.
А я может быть еще на что‑нибудь сподоблюсь.
Удачи!