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

При создании интерфейсов, тайловых полей или декоративных элементов часто требуется расположить множество игровых объектов в виде ровной сетки. Ручной расчет координат для каждого спрайта — утомительная и подверженная ошибкам задача. 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('diamonds', 'assets/sprites/diamonds32x24x5.png', { frameWidth: 32, frameHeight: 24 });
    }

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

        const group = this.add.group({
            key: 'diamonds',
            frame: [ 0, 1, 2, 3, 4 ],
            frameQuantity: 40
        });

        Phaser.Actions.GridAlign(group.getChildren(), {
            width: 20,
            height: 10,
            cellWidth: 32,
            cellHeight: 32,
            x: 80,
            y: 140
        });
    }
}

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

const game = new Phaser.Game(config);

Подготовка группы спрайтов

Перед выравниванием необходимо создать группу объектов. В Phaser группа (Group) — это удобный контейнер для управления множеством однотипных игровых объектов (спрайтов, изображений). В методе create мы загружаем фон и создаем группу из спрайтов алмазов.

const group = this.add.group({
    key: 'diamonds',
    frame: [ 0, 1, 2, 3, 4 ],
    frameQuantity: 40
});

Здесь мы создаем группу с ключом 'diamonds' (загруженный спрайтшит). Параметр frame — это массив индексов кадров (фреймов) из спрайтшита, которые будут использованы. Параметр frameQuantity указывает общее количество создаваемых спрайтов (40). Phaser равномерно распределит указанные фреймы среди всех созданных объектов. В итоге в группе окажется 40 спрайтов-алмазов пяти разных цветов.

Магия Phaser.Actions.GridAlign

Когда группа создана, но все спрайты находятся в одной точке (0, 0 по умолчанию), наступает время для Phaser.Actions.GridAlign. Этот статический метод принимает массив объектов и конфигурационный объект, а затем пересчитывает координаты (`x,y`) каждого переданного объекта, располагая их по сетке.

Phaser.Actions.GridAlign(group.getChildren(), {
    width: 20,
    height: 10,
    cellWidth: 32,
    cellHeight: 32,
    x: 80,
    y: 140
});

Первый аргумент — group.getChildren() — это массив всех спрайтов, содержащихся в группе. Второй аргумент — объект с настройками сетки.

Разбираем параметры выравнивания

Конфигурационный объект GridAlign дает полный контроль над расположением сетки. Давайте разберем каждое свойство:

{
    width: 20,   // Количество столбцов в сетке
    height: 10,  // Количество строк в сетке
    cellWidth: 32, // Ширина одной ячейки в пикселях
    cellHeight: 32,// Высота одной ячейки в пикселях
    x: 80,       // Начальная координата X для всей сетки
    y: 140       // Начальная координата Y для всей сетки
}

* width и height: Определяют размерность сетки (20x10). Метод берет первые width * height объектов из переданного массива (в нашем случае 20*10=200, но у нас только 40 спрайтов). Объекты заполняют сетку построчно, слева направо. * cellWidth и cellHeight: Задают размер ячейки. Координаты каждого следующего спрайта в строке увеличиваются на cellWidth, а при переходе на новую строку — на cellHeight. * `xиy`: Это координаты верхнего левого угла всей сетки на игровом поле. Все расчеты позиций начинаются от этой точки.

Как работает алгоритм выравнивания

Метод проходит по массиву объектов в цикле, вычисляя позицию для каждого на основе его индекса в массиве. Псевдологика расчета позиции для объекта с индексом `i` выглядит так:

// Вычисление столбца и строки для текущего объекта
let column = i % width; // Остаток от деления — позиция в строке
let row = Math.floor(i / width); // Целая часть от деления — номер строки

// Расчет финальных координат
object.x = startX + (column * cellWidth);
object.y = startY + (row * cellHeight);

Таким образом, первый объект (i=0) попадет в ячейку (0,0), второй (i=1) — в (1,0), двадцатый (i=19) — в (19,0), а двадцать первый (i=20) — уже на новую строку, в ячейку (0,1). Phaser делает это автоматически для всех переданных объектов.

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

Phaser.Actions.GridAlign — это невероятно полезный инструмент для быстрого и аккуратного расположения объектов. Он избавляет от необходимости писать вложенные циклы и ручные расчеты координат. Для экспериментов попробуйте изменить параметры cellWidth и cellHeight, чтобы создать разреженную или плотную сетку. Или используйте Phaser.Actions.RandomRectangle для хаотичного, но вписанного в заданную область, размещения объектов из той же группы. Комбинируя разные методы из класса Phaser.Actions, вы можете создавать сложные паттерны и анимации начального расположения игровых элементов.