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

Статичный фон — это скучно. В игровых сценах часто требуется плавное движение фоновых элементов: вращающиеся туманности, медленно плывущие облака или мерцающие звёзды. В этом примере показан простой, но мощный паттерн анимации, который работает независимо от частоты кадров, обеспечивая плавность на любом устройстве. Мы разберем, как использовать метод `update` для непрерывного изменения свойств игрового объекта, таких как вращение (`rotation`). Этот подход лежит в основе создания динамичных и живых сцен без использования тяжеловесных анимаций через спрайт-листы или твины.

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

Живой запуск

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

Исходный код


class SceneA extends Phaser.Scene {

    constructor ()
    {
        super('SceneA');

        this.nebula;
    }

    create ()
    {
        this.cameras.main.setViewport(0, 136, 1024, 465);

        this.nebula = this.add.image(300, 250, 'space', 'nebula');
    }

    update (time, delta)
    {
        this.nebula.rotation += 0.00006 * delta;
    }

}

Структура сцены и инициализация

Класс сцены наследуется от Phaser.Scene. В конструкторе мы задаем уникальный ключ сцены и объявляем свойство для хранения ссылки на наш объект.

class SceneA extends Phaser.Scene {
    constructor ()
    {
        super('SceneA');
        this.nebula;
    }

- super('SceneA') — передает ключ сцены в родительский конструктор. Этот ключ используется для запуска или переключения между сценами. - this.nebula; — объявление свойства класса. На этом этапе оно равно undefined. Инициализация произойдет позже, в методе create.

Создание объектов и настройка камеры

Метод create выполняется один раз при запуске сцены. Здесь мы размещаем игровые объекты и настраиваем окружение.

create ()
{
    this.cameras.main.setViewport(0, 136, 1024, 465);
    this.nebula = this.add.image(300, 250, 'space', 'nebula');
}
- `this.cameras.main.setViewport(0, 136, 1024, 465)` — определяет прямоугольную область (вьюпорт), которую занимает эта камера на общем игровом холсте. Это полезно для разделения экрана между несколькими сценами.
- `this.add.image(300, 250, 'space', 'nebula')` — создает объект `Image`. Аргументы: позиция X (300), позиция Y (250), ключ текстуры атласа (`'space'`), ключ кадра внутри этого атласа (`'nebula'`). Созданный объект сохраняется в свойство `this.nebula` для последующего доступа.

Цикл обновления и независимая от FPS анимация

Сердце анимации — метод update. Он вызывается на каждом кадре игры. Чтобы движение было плавным и не зависело от производительности, мы используем параметр delta.

update (time, delta)
{
    this.nebula.rotation += 0.00006 * delta;
}

- update (time, delta)time — общее время работы игры в миллисекундах, delta — время, прошедшее с предыдущего кадра, в миллисекундах. - this.nebula.rotation += 0.00006 * delta — ключевая строка. Мы увеличиваем свойство rotation (вращение в радианах) изображения на очень маленькую величину (0.00006), умноженную на delta.

**Почему это работает?** Без delta объект вращался бы с постоянной *скоростью за кадр*. На мощном ПК с 120 FPS (delta ≈ 8.3 мс) вращение было бы в два раза быстрее, чем на слабом устройстве с 60 FPS (delta ≈ 16.6 мс). Умножая базовую скорость на delta, мы получаем *скорость за миллисекунду*. Таким образом, за одну реальную секунду объект повернется на одно и то же значение, независимо от количества кадров. Константа 0.00006 подобрана экспериментально для визуально медленного и приятного вращения.

Практические вариации и идеи

Шаблон свойство += скорость * delta универсален. Вот что еще можно анимировать:

// Плавное движение по оси X (влево)
this.nebula.x -= 0.05 * delta;


// Плавное изменение масштаба (пульсация)
this.nebula.scaleX = 1.0 + Math.sin(time * 0.001) * 0.1;
this.nebula.scaleY = 1.0 + Math.sin(time * 0.001) * 0.1;


// Медленное смещение текстуры (прокрутка фона)
this.nebula.tilePositionX += 0.1 * delta;

- Первый пример — линейное движение. Используйте его для фонов, которые медленно дрейфуют. - Второй пример использует time и синусоиду для создания циклической пульсации объекта. - Третий пример работает, если nebula является тайловой спрайтом (this.add.tileSprite). Он создает эффект бесконечно прокручивающегося фона.

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

Использование метода update с параметром delta — это фундаментальный и производительный способ создания плавных, независящих от частоты кадров анимаций в Phaser 3. Он идеально подходит для фоновых элементов, атмосферных эффектов и постоянного движения. **Экспериментируйте:** Попробуйте применить этот подход к другим свойствам, например alpha (прозрачность) для эффекта мерцания, или объедините несколько изменений для сложного поведения. Создайте сцену с несколькими фоновыми слоями, движущимися с разной скоростью (параллакс-эффект), используя один и тот же принцип.