О чем этот пример
При создании игровых интерфейсов, инвентарей или карточных игр часто возникает задача расположить множество объектов по сетке. Вручную рассчитывать координаты для каждого спрайта — утомительно и чревато ошибками. 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.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');
}
create ()
{
this.add.image(400, 300, 'bg');
const frames = this.textures.get('cards').getFrameNames();
const cards = [];
// Create 8 cards and push them into an array
for (var i = 0; i < 8; i++)
{
cards.push(this.add.sprite(0, 0, 'cards', Phaser.Math.RND.pick(frames)));
}
// The cards are 140x190 in size
// Let's lay them out in a 4x2 grid, with 10px spacing between them
Phaser.Actions.GridAlign(cards, {
width: 4,
height: 2,
cellWidth: 150,
cellHeight: 200,
x: 100,
y: 100
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Зачем нужен GridAlign?
Представьте, что вам нужно отобразить колоду карт, элементы инвентаря или ряд кнопок меню. Каждый объект имеет свои координаты (x, y). Чтобы расположить их ровными рядами и колонками, нужно для каждого рассчитывать позицию, учитывая его индекс, размер ячейки и отступы. Phaser.Actions.GridAlign автоматизирует этот процесс.
Метод принимает массив игровых объектов (спрайтов, изображений, текста) и конфигурационный объект, а затем мгновенно расставляет все элементы по заданной сетке. Это не только экономит время, но и делает код чище и легче для поддержки.
Подготовка сцены и создание спрайтов
В первую очередь, как и в любом проекте Phaser, нужно загрузить ресурсы и создать сцену. В методе preload загружаем фон и атлас спрайтов с картами.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('bg', 'assets/skies/deepblue.png');
this.load.atlas('cards', 'assets/atlas/cards.png', 'assets/atlas/cards.json');
}
В методе create добавляем фон и готовим массив для будущих карт. Ключевой момент: мы создаем спрайты с нулевыми координатами (0, 0). Их фактическое положение будет задано позже.
create ()
{
this.add.image(400, 300, 'bg');
const frames = this.textures.get('cards').getFrameNames();
const cards = [];
for (var i = 0; i < 8; i++)
{
cards.push(this.add.sprite(0, 0, 'cards', Phaser.Math.RND.pick(frames)));
}
}
Цикл создает 8 спрайтов-карт, выбирая для каждого случайный кадр (frame) из атласа, и помещает их в массив cards. Пока все они находятся в одной точке (в верхнем левом углу мира).
Магия GridAlign: настройка сетки
Вот где происходит основное действие. Мы вызываем Phaser.Actions.GridAlign, передавая массив объектов и объект настроек.
Phaser.Actions.GridAlign(cards, {
width: 4,
height: 2,
cellWidth: 150,
cellHeight: 200,
x: 100,
y: 100
});
Разберем параметры конфигурации:
* width: 4 и height: 2 — определяют размерность сетки (4 колонки, 2 строки). Всего 8 ячеек, что идеально соответствует нашему массиву из 8 карт.
* cellWidth: 150 и cellHeight: 200 — задают размер одной ячейки сетки. Эти значения должны быть немного больше размера самого спрайта (140x190), чтобы оставался промежуток (padding).
* x: 100 и y: 100 — координаты верхнего левого угла всей сетки. От этой точки начинается расчет позиций для всех объектов.
Метод проходит по массиву cards и для каждого элемента вычисляет его окончательные координаты, основываясь на его индексе в массиве и заданных параметрах сетки. Первый объект попадает в ячейку [0,0], второй — в [1,0], и так далее, построчно.
Конфигурация игры и запуск
Завершающий шаг — стандартная настройка объекта конфигурации Phaser Game и его создание.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Эта конфигурация создает игровое поле размером 800x600 пикселей с темно-серым фоном и запускает нашу сцену Example. После запуска вы увидите 8 различных карт, аккуратно разложенных в два ряда по четыре штуки.
Что попробовать дальше
Phaser.Actions.GridAlign — это мощный и простой инструмент для организации игровых объектов. Он избавляет от рутинных расчетов и позволяет управлять layout'ом через понятные параметры. Для экспериментов попробуйте: изменить параметры width и height на 2x4; динамически добавлять новые карты в массив и заново применять GridAlign; использовать разные значения cellWidth и cellHeight для создания неравномерных сеток; или применить этот метод не к спрайтам, а к текстовым объектам для создания меню.
