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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    constructor ()
    {
        super();
    }

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('bg', 'assets/skies/deepblue.png');
        this.load.spritesheet('sotb', 'assets/animations/sotb-64x112x11.png', { frameWidth: 64, frameHeight: 112 });
    }

    create ()
    {
        this.add.image(400, 300, 'bg');

        this.anims.create({
            key: 'walk',
            frames: this.anims.generateFrameNumbers('sotb'),
            frameRate: 16,
            repeat: -1
        });

        const sprites = [];

        for (var i = 0; i < 60; i++)
        {
            sprites.push(this.add.sprite(0, 0, 'sotb').play('walk'));
        }

        //  The sprites are 64x112 in size

        //  Let's lay them out in a grid 12 sprites wide, by as many tall as we have sprites in the array for

        Phaser.Actions.GridAlign(sprites, {
            width: 12,
            cellWidth: 64,
            cellHeight: 120,
            x: 16,
            y: 4
        });
    }
}

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

const game = new Phaser.Game(config);

Подготовка сцены и загрузка ресурсов

В методе preload мы загружаем два ресурса: фоновое изображение ('bg') и спрайтшит ('sotb'). Спрайтшит — это изображение, содержащее несколько кадров анимации в одной текстуре. При загрузке мы указываем его ключ, путь и размер одного кадра (64x112 пикселя). Это необходимо для корректного создания анимации.

this.load.image('bg', 'assets/skies/deepblue.png');
this.load.spritesheet('sotb', 'assets/animations/sotb-64x112x11.png', { frameWidth: 64, frameHeight: 112 });

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

В методе create сначала добавляется фон. Затем создаётся анимация с ключом 'walk'. Функция this.anims.generateFrameNumbers('sotb') автоматически генерирует массив кадров из всего загруженного спрайтшита. Параметр repeat: -1 задаёт бесконечное повторение анимации.

Далее в цикле создаётся 60 спрайтов. Каждый из них использует текстуру 'sotb', добавляется в сцену в точке (0, 0) и сразу начинает проигрывать анимацию 'walk'. Все созданные спрайты сохраняются в массив sprites.

this.anims.create({
    key: 'walk',
    frames: this.anims.generateFrameNumbers('sotb'),
    frameRate: 16,
    repeat: -1
});

const sprites = [];
for (var i = 0; i < 60; i++)
{
    sprites.push(this.add.sprite(0, 0, 'sotb').play('walk'));
}

Магия выравнивания: Phaser.Actions.GridAlign

Вся логика упорядочивания заключена в один вызов Phaser.Actions.GridAlign. Этот метод принимает массив игровых объектов (в нашем случае — спрайтов) и объект конфигурации. Он перебирает массив и расставляет объекты в сетке согласно заданным правилам.

Ключевые параметры конфига: * width: 12 — количество столбцов в сетке. Всего 60 спрайтов, поэтому получится 5 строк (60 / 12). * cellWidth: 64 и cellHeight: 120 — размер ячейки сетки. Ширина равна ширине спрайта (64), а высота (120) чуть больше высоты спрайта (112), чтобы создать отступ между строками. * x: 16 и y: 4 — смещение всей сетки от левого верхнего угла сцены. Это позволяет создать поля.

Метод автоматически рассчитывает координаты для каждого спрайта и присваивает их его свойству position.

Phaser.Actions.GridAlign(sprites, {
    width: 12,
    cellWidth: 64,
    cellHeight: 120,
    x: 16,
    y: 4
});

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

Объект config определяет базовые настройки игрового экземпляра Phaser. Здесь задаётся тип рендерера (Phaser.AUTO), размеры холста (800x600), цвет фона (на случай, если фон не загрузится), ID HTML-элемента для встраивания и стартовая сцена (Example). В конце конфигурация передаётся в конструктор new Phaser.Game(config) для запуска игры.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    scene: Example
};
const game = new Phaser.Game(config);

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

Phaser.Actions.GridAlign — это мощный и лаконичный способ организовать множество игровых объектов в структурированную композицию. Он избавляет от написания громоздких циклов с расчётом координат. Для экспериментов попробуйте: изменить параметры width, cellHeight или `x,y; использовать другой метод из семействаActions, например,PlaceOnLineилиPlaceOnCircle; или применитьGridAlign` не к спрайтам, а к контейнерам с интерактивными элементами для построения сложных меню.