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

В разработке игр часто возникает задача анимировать или перемещать группу игровых объектов одновременно. Phaser предоставляет для этого мощный инструмент — `Container`. Эта статья покажет, как использовать контейнер для объединения нескольких анимированных спрайтов и применения к ним комплексных трансформаций одной инструкцией. Вы научитесь создавать сложные составные объекты, что особенно полезно для интерфейсов, боссов или многосоставных персонажей.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.spritesheet('mummy', 'assets/sprites/metalslug_mummy37x45.png', { frameWidth: 37, frameHeight: 45, endFrame: 17 });
    }

    create ()
    {
        this.anims.create({
            key: 'run',
            frames: 'mummy',
            frameRate: 20,
            repeat: -1
        });

        const sprite1 = this.add.sprite(100, 200, 'mummy').play('run');
        const sprite2 = this.add.sprite(100, 300, 'mummy').play('run');
        const sprite3 = this.add.sprite(100, 400, 'mummy').play('run');

        const container = this.add.container(300, 0, [ sprite1, sprite2, sprite3 ]);

        this.tweens.add({
            targets: container,
            scaleX: 3,
            scaleY: 3,
            duration: 6000,
            yoyo: true,
            repeat: -1
        });
    }
}

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

const game = new Phaser.Game(config);

Загрузка ресурсов и создание анимации

Работа начинается с подготовки. В методе preload мы загружаем спрайтшит — набор кадров для анимации. Ключ 'mummy' будет использоваться для ссылки на этот ресурс.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.spritesheet('mummy', 'assets/sprites/metalslug_mummy37x45.png', { frameWidth: 37, frameHeight: 45, endFrame: 17 });
}

Далее, в create, мы создаем анимацию. Указываем ключ 'run', источник кадров (загруженный спрайтшит 'mummy'), частоту смены кадров и параметр бесконечного повтора.

this.anims.create({
    key: 'run',
    frames: 'mummy',
    frameRate: 20,
    repeat: -1
});

Создание спрайтов и их анимирование

Теперь создадим три отдельных спрайта, используя текстуру 'mummy'. Сразу после создания каждого спрайта мы запускаем на нем анимацию 'run' с помощью метода .play(). Это позволяет видеть, что каждый мумия 'бежит' независимо.

const sprite1 = this.add.sprite(100, 200, 'mummy').play('run');
const sprite2 = this.add.sprite(100, 300, 'mummy').play('run');
const sprite3 = this.add.sprite(100, 400, 'mummy').play('run');

Обратите внимание, что изначально все спрайты имеют координаты X=100, но разные координаты Y, поэтому они отображаются вертикальным столбцом.

Объединение объектов в контейнер

Вот ключевой шаг. Мы создаем контейнер, передавая ему начальные координаты (300, 0) и массив дочерних объектов — наших трех спрайтов.

const container = this.add.container(300, 0, [ sprite1, sprite2, sprite3 ]);

Контейнер становится родителем для этих спрайтов. Теперь их позиция, масштаб, угол поворота и видимость вычисляются относительно позиции контейнера. Исходные координаты спрайтов (100, 200 и т.д.) становятся их *локальными* координатами внутри контейнера.

Анимация контейнера с помощью Tween

Сила контейнеров проявляется при анимации. Мы создаем твин, который масштабирует весь контейнер по осям X и Y до размера 3 (то есть, в три раза).

this.tweens.add({
    targets: container,
    scaleX: 3,
    scaleY: 3,
    duration: 6000,
    yoyo: true,
    repeat: -1
});

Параметр targets указывает на контейнер. Параметры yoyo: true и repeat: -1 заставляют анимацию плавно возвращаться к исходному масштабу и повторяться бесконечно. В результате все три спрайта масштабируются и двигаются вместе, как единый объект, сохраняя при этом свои индивидуальные анимации.

Настройка игры (Config)

Код завершается стандартной конфигурацией игры Phaser, где указывается наш класс сцены Example.

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

const game = new Phaser.Game(config);

Темный фон (#010101) хорошо контрастирует со спрайтами, делая анимацию четко видимой.

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

Контейнеры в Phaser — это простой и эффективный способ группировки игровых объектов для совместного управления. Как показано в примере, вы можете анимировать, перемещать и трансформировать сложные композиции одной командой. Для экспериментов попробуйте: добавить вращение контейнеру с помощью свойства angle, анимировать его позицию `xилиy, динамически добавлять и удалять дочерние объекты методомcontainer.add()` или менять их порядок отрисовки. Это откроет путь к созданию сложных игровых механик.