О чем этот пример
В игровых проектах часто требуется управлять множеством однотипных объектов — врагами, пулями, бонусами. Ручное создание каждого из них быстро становится неудобным. В этой статье мы разберем, как использовать мощный инструмент Phaser — группы (Groups) — для эффективного создания и управления рядами спрайтов на примере классической армады космических захватчиков. Вы научитесь быстро генерировать отряды врагов, позиционировать их с заданным шагом и применять массовые действия ко всем элементам группы.
Версия 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.spritesheet('invader1', 'assets/tests/invaders/invader1.png', { frameWidth: 32, frameHeight: 32 });
this.load.spritesheet('invader2', 'assets/tests/invaders/invader2.png', { frameWidth: 44, frameHeight: 32 });
this.load.spritesheet('invader3', 'assets/tests/invaders/invader3.png', { frameWidth: 48, frameHeight: 32 });
}
create ()
{
const invader1 = this.add.group({ key: 'invader1', frame: 0, repeat: 13, setXY: { x: 32, y: 100, stepX: 40 } });
const invader2 = this.add.group([
{ key: 'invader2', frame: 0, repeat: 10, setXY: { x: 32, y: 148, stepX: 52 } },
{ key: 'invader2', frame: 0, repeat: 10, setXY: { x: 32, y: 148 + 48, stepX: 52 } }
]);
const invader3 = this.add.group([
{ key: 'invader3', frame: 0, repeat: 9, setXY: { x: 32, y: 148 + 96, stepX: 58 } },
{ key: 'invader3', frame: 0, repeat: 9, setXY: { x: 32, y: 148 + 96 + 48, stepX: 58 } }
]);
Phaser.Actions.IncX(invader1.getChildren(), 100);
Phaser.Actions.IncX(invader2.getChildren(), 100);
Phaser.Actions.IncX(invader3.getChildren(), 100);
Phaser.Actions.SetTint(invader1.getChildren(), 0xff0000);
Phaser.Actions.SetTint(invader2.getChildren(), 0x00ff00);
Phaser.Actions.SetTint(invader3.getChildren(), 0x00ffff);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Загрузка ресурсов и настройка группы
Перед созданием группы необходимо загрузить графические ресурсы. В методе preload мы используем this.load.spritesheet, чтобы загрузить три разных спрайтшита с пришельцами, указывая ширину и высоту каждого кадра.
this.load.spritesheet('invader1', 'assets/tests/invaders/invader1.png', { frameWidth: 32, frameHeight: 32 });
this.load.spritesheet('invader2', 'assets/tests/invaders/invader2.png', { frameWidth: 44, frameHeight: 32 });
this.load.spritesheet('invader3', 'assets/tests/invaders/invader3.png', { frameWidth: 48, frameHeight: 32 });
Создание группы начинается в методе create. Самый простой способ — использовать this.add.group, передав объект конфигурации. Ключевые параметры:
- key: ключ загруженного изображения.
- frame: номер кадра из спрайтшита (в нашем случае 0).
- repeat: количество *дополнительных* создаваемых объектов. Итоговое количество = repeat + 1.
- setXY: объект, задающий позицию первого элемента и шаг по оси X для последующих.
const invader1 = this.add.group({ key: 'invader1', frame: 0, repeat: 13, setXY: { x: 32, y: 100, stepX: 40 } });
Эта строка создает группу invader1, состоящую из 14 спрайтов (1 + 13 повторов). Первый пришелец будет размещен в точке (32, 100), а каждый следующий — на 40 пикселей правее (stepX: 40).
Создание сложных формаций через массив конфигов
Что если нужно создать несколько рядов пришельцев одного типа? Для этого this.add.group может принимать массив объектов конфигурации. Каждый элемент массива создает свой ряд объектов с заданными параметрами.
const invader2 = this.add.group([
{ key: 'invader2', frame: 0, repeat: 10, setXY: { x: 32, y: 148, stepX: 52 } },
{ key: 'invader2', frame: 0, repeat: 10, setXY: { x: 32, y: 148 + 48, stepX: 52 } }
]);
В этом примере создается группа invader2, содержащая два ряда. В каждом ряду по 11 пришельцев (1 + 10 повторов). Первый ряд начинается с координаты Y = 148, второй — на 48 пикселей ниже (148 + 48). Шаг между пришельцами в ряду (stepX) равен 52 пикселя, что соответствует ширине спрайта (44px) плюс небольшой отступ.
Аналогично создается группа invader3 с еще двумя рядами, расположенными еще ниже и с большим шагом (stepX: 58), так как эти спрайты шире (48px).
Массовые операции с элементами групп
После создания групп часто требуется применить одно действие ко всем их элементам. Phaser предоставляет для этого утилиты Phaser.Actions. Они работают с массивами игровых объектов. Чтобы получить такой массив из группы, используем метод getChildren().
Сначала сдвинем все созданные ряды пришельцев вправо на 100 пикселей. Phaser.Actions.IncX увеличивает координату X каждого объекта в переданном массиве на указанное значение.
Phaser.Actions.IncX(invader1.getChildren(), 100);
Phaser.Actions.IncX(invader2.getChildren(), 100);
Phaser.Actions.IncX(invader3.getChildren(), 100);
Затем окрасим ряды в разные цвета с помощью Phaser.Actions.SetTint. Этот метод применяет тонирование (tint) к каждому спрайту в массиве. Цвет задается в шестнадцатеричном формате (0xRRGGBB).
Phaser.Actions.SetTint(invader1.getChildren(), 0xff0000); // Красный
Phaser.Actions.SetTint(invader2.getChildren(), 0x00ff00); // Зеленый
Phaser.Actions.SetTint(invader3.getChildren(), 0x00ffff); // Голубой
Эти действия демонстрируют мощь групп: управление десятками объектов сводится к нескольким строкам кода.
Конфигурация игры и запуск сцены
Весь описанный код находится внутри класса сцены Example. Чтобы игра заработала, необходимо создать конфигурационный объект и передать его в конструктор Phaser.Game.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Ключевые параметры конфига:
- type: Phaser.AUTO позволяет Phaser самому выбрать рендерер (WebGL или Canvas).
- width / height: размер игрового холста.
- backgroundColor: цвет фона (черный).
- parent: ID HTML-элемента, в который будет вставлен canvas. Если элемента с таким ID нет, canvas будет добавлен в тело документа.
- scene: класс нашей сцены, которая будет запущена сразу после инициализации игры.
После создания экземпляра game Phaser автоматически вызовет методы жизненного цикла сцены (preload, create, update).
Что попробовать дальше
Группы в Phaser — это фундаментальный инструмент для организации множества однотипных игровых объектов. Они не только упрощают создание и расстановку, но и открывают доступ к мощным массовым операциям через Phaser.Actions. Для экспериментов попробуйте: изменить параметры repeat и stepX для создания более плотных или разреженных формаций; использовать Phaser.Actions.Call для вызова пользовательской функции у каждого элемента группы; добавить группе физическое тело для коллективного управления столкновениями и движением.
