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

В Phaser контейнеры (`Container`) — это мощный инструмент для организации игровых объектов. Они позволяют управлять группой спрайтов как единым целым: перемещать, вращать и масштабировать все дочерние элементы одновременно. В этой статье мы разберем, как добавлять объекты в контейнер и, что особенно полезно, как вставлять их на определенную позицию в списке с помощью метода `addAt`. Это ключевой прием для контроля порядка отрисовки (z-index) внутри контейнера.

Версия 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.image('rick', 'assets/sprites/rick.png');
    }

    create ()
    {
        //  Our container
        const container = this.add.container(400, 300);

        //  Create some sprites - positions are relative to the Container x/y
        const sprite0 = this.add.sprite(-200, 0, 'rick');
        const sprite1 = this.add.sprite(0, 0, 'rick');
        const sprite2 = this.add.sprite(200, 0, 'rick');
        const sprite3 = this.add.sprite(-100, -100, 'rick');
        const sprite4 = this.add.sprite(100, -100, 'rick');
        const sprite5 = this.add.sprite(100, 100, 'rick');

        container.add([ sprite0, sprite1, sprite2 ]);

        container.addAt([ sprite3, sprite4, sprite5 ], 0);

        this.tweens.add({
            targets: container,
            angle: { value: 360, duration: 6000 },
            scaleX: { value: 0.5, duration: 3000, yoyo: true, ease: 'Quad.easeInOut' },
            scaleY: { value: 0.5, duration: 3000, yoyo: true, ease: 'Quad.easeInOut' },
            repeat: -1
        });
    }
}

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

const game = new Phaser.Game(config);

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

Основой для группировки является объект Container. Его координаты становятся новой точкой отсчета для всех добавленных в него дочерних элементов.

Создаем контейнер в центре экрана и несколько спрайтов. Обратите внимание: координаты спрайтов задаются относительно будущего родителя — контейнера.

const container = this.add.container(400, 300);

const sprite0 = this.add.sprite(-200, 0, 'rick');
const sprite1 = this.add.sprite(0, 0, 'rick');
const sprite2 = this.add.sprite(200, 0, 'rick');
const sprite3 = this.add.sprite(-100, -100, 'rick');
const sprite4 = this.add.sprite(100, -100, 'rick');
const sprite5 = this.add.sprite(100, 100, 'rick');

Базовое добавление объектов: метод add

Метод add позволяет добавить один объект или массив объектов в контейнер. Добавленные объекты помещаются в конец внутреннего списка. Порядок в этом списке определяет последовательность отрисовки: элементы с большим индексом рисуются поверх элементов с меньшим индексом.

container.add([ sprite0, sprite1, sprite2 ]);

Теперь в контейнере находятся sprite0, sprite1 и sprite2 именно в таком порядке. Спрайт sprite2 будет отрисован поверх остальных.

Вставка на определенную позицию: метод addAt

Вот где начинается настоящий контроль. Метод addAt вставляет один объект или массив объектов в указанный индекс списка контейнера. Это позволяет поместить объекты "под" или "над" уже существующими.

container.addAt([ sprite3, sprite4, sprite5 ], 0);

Мы вставляем три новых спрайта в самое начало списка (индекс 0). Теперь порядок объектов в контейнере такой: [sprite3, sprite4, sprite5, sprite0, sprite1, sprite2]. Визуально это означает, что первые три добавленных спрайта (sprite0, sprite1, sprite2) теперь будут отрисованы поверх трех новых, так как имеют больший индекс.

Преобразование всего контейнера

Главное преимущество контейнера — возможность применять трансформации ко всем его детям сразу. В примере создается твин, который вращает и масштабирует контейнер. Все спрайты внутри него будут вести себя как единый жесткий объект.

this.tweens.add({
    targets: container,
    angle: { value: 360, duration: 6000 },
    scaleX: { value: 0.5, duration: 3000, yoyo: true, ease: 'Quad.easeInOut' },
    scaleY: { value: 0.5, duration: 3000, yoyo: true, ease: 'Quad.easeInOut' },
    repeat: -1
});

Мы анимируем сам контейнер (targets: container). Его свойства angle, scaleX и scaleY изменяются, и эти изменения автоматически применяются ко всем дочерним спрайтам.

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

Контейнеры в Phaser — это фундаментальный инструмент для структурирования сложных игровых объектов, таких как персонажи из нескольких частей, интерфейсы или уровни. Метод addAt дает вам точный контроль над порядком отрисовки внутри этой группы. Для экспериментов попробуйте: 1. Менять индекс в вызове addAt и наблюдать за изменением наложения спрайтов. 2. Добавлять в контейнер другие типы объектов: текст, графику или даже другие контейнеры. 3. Применять к контейнеру физические свойства через this.physics.add.container и наблюдать за коллективным поведением.