О чем этот пример
При создании игр часто возникает задача анимировать множество одинаковых объектов, например, монет, врагов или частиц эффекта. Воспроизводить анимацию для всех объектов одновременно может выглядеть скучно и неестественно. Метод `anims.staggerPlay` в Phaser решает эту проблему, позволяя запускать анимацию на группе объектов с задержкой между каждым запуском. Это создает эффект волны или цепной реакции, который оживляет сцену и добавляет визуальную динамику. В этой статье мы разберем, как использовать этот метод на практическом примере с сеткой из спрайтов.
Версия 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.spritesheet('diamonds', 'assets/sprites/diamonds32x24x5.png', { frameWidth: 32, frameHeight: 24 });
}
create ()
{
const config = {
key: 'flash',
frames: this.anims.generateFrameNumbers('diamonds', { start: 0, end: 4 }),
frameRate: 1,
repeat: -1
};
this.anims.create(config);
const group = this.add.group();
group.createMultiple({ key: 'diamonds', frame: 0, repeat: 279 });
Phaser.Actions.GridAlign(group.getChildren(), {
width: 20,
height: 20,
cellWidth: 38,
x: 19,
y: 25
});
this.anims.staggerPlay('flash', group.getChildren(), 60);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Подготовка анимации и создание группы спрайтов
Перед использованием staggerPlay необходимо создать анимацию и группу объектов, которые будут её проигрывать. В методе preload загружается спрайтшит, содержащий кадры для анимации. В create сначала создается конфигурация анимации, а затем группа, заполненная множеством спрайтов.
const config = {
key: 'flash',
frames: this.anims.generateFrameNumbers('diamonds', { start: 0, end: 4 }),
frameRate: 1,
repeat: -1
};
this.anims.create(config);
const group = this.add.group();
group.createMultiple({ key: 'diamonds', frame: 0, repeat: 279 });
Ключевые моменты:
- key: 'flash' — уникальное имя анимации для последующего вызова.
- generateFrameNumbers — генерирует массив кадров из спрайтшита 'diamonds' с индексами от 0 до 4.
- repeat: -1 — анимация будет зациклена бесконечно.
- group.createMultiple — создает 280 спрайтов (1 начальный + 279 повторов) с начальным кадром frame: 0.
Выравнивание объектов в сетку
Чтобы объекты группы отображались упорядоченно, используется Phaser.Actions.GridAlign. Этот метод распределяет дочерние элементы группы по виртуальной сетке с заданными параметрами.
Phaser.Actions.GridAlign(group.getChildren(), {
width: 20,
height: 20,
cellWidth: 38,
x: 19,
y: 25
});
Параметры конфигурации:
- width: 20 и height: 20 — определяют размер сетки 20x20, что идеально подходит для 280 спрайтов (14 строк * 20 столбцов = 280).
- cellWidth: 38 — задает горизонтальное расстояние между центрами спрайтов. Значение больше ширины спрайта (32px) предотвращает наложение.
- x: 19 и y: 25 — смещение начальной позиции сетки от левого верхнего угла сцены.
Метод group.getChildren() возвращает массив всех созданных спрайтов для операции выравнивания.
Запуск анимации с задержкой
Самый важный этап — вызов this.anims.staggerPlay. Этот метод запускает указанную анимацию на всех объектах массива, но не одновременно, а с заданным временным интервалом между запусками для каждого следующего объекта.
this.anims.staggerPlay('flash', group.getChildren(), 60);
Аргументы метода:
1. 'flash' — ключ анимации, которую нужно проигрывать. Должен совпадать с key в конфигурации, созданной ранее.
2. group.getChildren() — массив игровых объектов (спрайтов), которые должны проигрывать анимацию.
3. 60 — задержка в миллисекундах между запуском анимации на одном объекте и на следующем. Значение 60 создает плавную волну.
В результате анимация 'flash' запустится на первом спрайте, через 60 мс — на втором, еще через 60 мс — на третьем и так далее, создавая эффект последовательного мерцания по сетке.
Как работает задержка и визуальный эффект
Задержка применяется не к кадрам самой анимации, а к моменту её старта на каждом объекте. Это означает, что все спрайты будут независимо проигрывать одну и ту же циклическую анимацию, но начало воспроизведения у них будет смещено во времени.
Поскольку в нашем примере анимация 'flash' имеет frameRate: 1 (один кадр в секунду) и состоит из 5 кадров, полный цикл на одном спрайте длится 5 секунд. Из-за staggerPlay с задержкой 60 мс, соседние спрайты в сетке будут находиться на разных фазах этого цикла. Это создает иллюзию бегущей волны или последовательного включения объектов, что гораздо интереснее, чем статичное синхронное мигание.
Важно: метод staggerPlay автоматически запускает анимацию на каждом переданном объекте. Вручную вызывать play для каждого спрайта не требуется.
Что попробовать дальше
Метод anims.staggerPlay — это мощный и простой инструмент для добавления динамики в сцены с множеством одинаковых анимированных объектов. Он избавляет от необходимости писать циклы с таймерами вручную. Для экспериментов попробуйте изменить параметр задержки на большее (например, 200) или меньшее (20) значение, чтобы увидеть, как меняется характер "волны". Также можно применить этот метод к объектам, выстроенным не в сетку, а, например, по окружности с помощью Phaser.Actions.PlaceOnCircle, чтобы создать спиральный или круговой эффект активации.
