О чем этот пример
При создании интерфейсов или игровых элементов (например, колоды карт) часто нужно расположить множество объектов по сетке. Стандартный `Phaser.Actions.GridAlign` делает это идеально, но с его помощью можно добиться и более интересных визуальных эффектов, например, перекрытия объектов. В этой статье мы разберем простой пример, где карты в колоде красиво накладываются друг на друга, создавая ощущение глубины и объема, используя только встроенные возможности движка Phaser 3.
Версия 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 < 16; 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 8x2 grid, except we'll use a smaller cell size, so that
// the cards overlap horizontally
Phaser.Actions.GridAlign(cards, {
width: 8,
height: 2,
cellWidth: 80,
cellHeight: 220,
x: 50,
y: 80
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ассетов
Как и в любой сцене Phaser, работа начинается с методов preload и create. В preload мы загружаем фоновое изображение и атлас спрайтов — набор карт. Использование атласа (atlas) эффективнее, чем загрузка множества отдельных изображений, так как уменьшает количество HTTP-запросов и оптимизирует использование памяти.
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 мы сначала добавляем фон, а затем получаем список всех доступных кадров (фреймов) из загруженного атласа cards. Это нужно для того, чтобы позднее случайным образом выбирать внешний вид каждой карты.
create ()
{
this.add.image(400, 300, 'bg');
const frames = this.textures.get('cards').getFrameNames();
}
Создание массива спрайтов
Для удобства манипуляций с группой объектов их нужно собрать в массив. Мы создаем пустой массив cards и в цикле создаем 16 спрайтов. Каждый спрайт изначально помещается в точку (0, 0), а его текстура и кадр задаются как cards и случайный фрейм из полученного ранее списка.
Ключевой момент: метод Phaser.Math.RND.pick(frames) случайным образом выбирает имя фрейма из массива frames. Это встроенный генератор случайных чисел Phaser.
const cards = [];
for (var i = 0; i < 16; i++)
{
cards.push(this.add.sprite(0, 0, 'cards', Phaser.Math.RND.pick(frames)));
}
Магия GridAlign: настройка перекрытия
Самый важный этап — использование Phaser.Actions.GridAlign. Этот метод принимает массив игровых объектов и объект конфигурации, а затем автоматически перераспределяет их координаты, выравнивая по сетке.
Стандартный подход предполагает, что cellWidth и cellHeight равны или больше размера объекта, чтобы избежать наложения. Однако для эффекта перекрытия (как в веерной колоде карт) мы задаем cellWidth меньше реальной ширины карты (140px). В примере используется cellWidth: 80. Это означает, что горизонтальное расстояние между центрами соседних карт будет всего 80 пикселей, что заставляет их заходить друг на друга.
Параметры width: 8 и height: 2 задают размер сетки (8 колонок, 2 строки). Параметры x: 50 и y: 80 определяют стартовую точку (верхний левый угол) для размещения всей сетки на сцене.
Phaser.Actions.GridAlign(cards, {
width: 8,
height: 2,
cellWidth: 80,
cellHeight: 220,
x: 50,
y: 80
});
Обратите внимание, что cellHeight (220) больше высоты карты (190), поэтому карты в разных строках не перекрываются по вертикали, создавая аккуратный двурядный макет.
Конфигурация игры
Код инициализации игры стандартен. В конфигурационном объекте мы задаем тип рендерера, размеры холста, цвет фона (который будет виден до загрузки ассетов), ID родительского HTML-элемента и класс нашей сцены.
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 — это мощный и гибкий инструмент для автоматического размещения объектов. Как мы увидели, его можно использовать не только для строгих сеток, но и для создания визуальных эффектов с наложением, меняя размеры ячеек. Для экспериментов попробуйте: изменить параметры cellWidth и cellHeight на динамические, зависящие от размера экрана; анимировать процесс раскладки карт с помощью Tweens; или применить GridAlign не к спрайтам, а к контейнерам с более сложной иерархией объектов.
