О чем этот пример

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

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    timeText;

    create ()
    {
        this.timeText = this.add.text(100, 200);
    }

    update (time, delta)
    {
        this.timeText.setText(`Time: ${time}\nDelta: ${delta}`);
    }
}

const config = {
    type: Phaser.CANVAS,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Зачем нужны `time` и `delta`?

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

Phaser решает эту проблему, передавая в метод update два параметра: time и delta. Они позволяют делать расчёты, основанные на реальном прошедшем времени, а не на количестве кадров. Это называется «независимость от частоты кадров» (frame rate independence).

Глобальное время игры: параметр `time`

Параметр time — это количество миллисекунд, прошедших с момента запуска игры. Это монотонно возрастающее значение, своего рода внутренние часы движка.

Чаще всего time используется для расчётов, требующих абсолютной временной точки: триггеров событий по расписанию, анимаций по кривым или синусоидальных движений.

В нашем примере мы просто выводим это значение на экран.

update (time, delta)
{
    // time содержит время в мс с момента старта игры
    this.timeText.setText(`Time: ${time}`);
}

Время между кадрами: параметр `delta`

Параметр delta — это самое важное значение для создания плавного движения. Он показывает, сколько миллисекунд прошло с момента вызова предыдущего update.

В идеальных условиях при 60 FPS delta будет примерно равен 16.66 мс. Если игра начнёт тормозить и следующий кадр отрисуется через 50 мс, значение delta будет равно 50.

Используя delta, вы можете перемещать объект с постоянной скоростью в пикселях в секунду, независимо от FPS.

update (time, delta)
{
    // Перемещаем спрайт со скоростью 100 пикселей в секунду
    // delta в миллисекундах, поэтому делим на 1000
    this.player.x += (100 * delta) / 1000;
}

Практическое применение: движение с постоянной скоростью

Вот как выглядит базовый шаблон для перемещения объекта. Скорость задаётся в пикселях в секунду, а delta обеспечивает корректное расстояние для перемещения за время между кадрами.

create ()
{
    this.sprite = this.physics.add.image(100, 300, 'player');
    // Скорость в пикселях в секунду
    this.speed = 200;
}

update (time, delta)
{
    // Пересчёт скорости с учётом дельты времени
    const velocity = (this.speed * delta) / 1000;
    this.sprite.x += velocity;
}

Этот подход гарантирует, что объект всегда пройдёт 200 пикселей за ровно одну секунду реального времени, даже если игра рендерится с разной частотой кадров.

Что попробовать дальше

Использование delta для всех расчётов, связанных со временем, — это фундаментальная практика в Phaser. Она делает вашу игру стабильной и предсказуемой на любом железе. Для экспериментов попробуйте создать метроном, который тикает раз в секунду, используя накопление значения delta, или анимируйте масштаб объекта по синусоиде, используя глобальное time для расчёта угла.