О чем этот пример
Анимация множества объектов по сложной схеме — частая задача в разработке игр, от визуальных эффектов до построения интерфейсов. В этом примере мы рассмотрим, как с помощью всего нескольких строк кода на Phaser 3 создать эффект "бегущей волны" масштабирования, распределённой по сетке, напоминающей переворачивание шахматных клеток. Вы научитесь эффективно работать с группами объектов (`Group`), выравнивать их в идеальную сетку с помощью `Phaser.Actions.GridAlign` и управлять сложными последовательностями анимаций через систему твинов (`Tweens`). Этот подход незаменим для создания динамичного фона, заставок или интерактивных элементов без ручного позиционирования каждого спрайта.
Версия 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/tweens/space.png');
this.load.image('block', 'assets/sprites/50x50.png');
}
create ()
{
this.add.image(400, 300, 'bg');
const blocks = this.add.group({ key: 'block', repeat: 107, setScale: { x: 0.3, y: 0.3 } });
Phaser.Actions.GridAlign(blocks.getChildren(), {
width: 12,
height: 9,
cellWidth: 60,
cellHeight: 60,
x: 40,
y: 30
});
let i = 0;
blocks.children.forEach(child => {
this.tweens.add({
targets: child,
scale: 1,
ease: 'sine.inout',
duration: 300,
delay: i * 50,
repeat: -1,
yoyo: true
});
i++;
if (i % 12 === 0)
{
i = 0;
}
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка ассетов
Как и в любой сцене Phaser, работа начинается с методов жизненного цикла. В preload мы загружаем два изображения: фон (bg) и небольшой квадратный спрайт (block), который станет нашим повторяющимся элементом.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('bg', 'assets/tweens/space.png');
this.load.image('block', 'assets/sprites/50x50.png');
}
В методе create первым делом добавляем фоновое изображение в центр холста. Координаты (400, 300) соответствуют центру, так как размер игры установлен в 800x600 пикселей.
Создание и выравнивание группы объектов
Вместо создания 108 спрайтов вручную, мы используем мощный инструмент Phaser — Group. Группа создаёт множество игровых объектов на основе одного ключа текстуры.
const blocks = this.add.group({ key: 'block', repeat: 107, setScale: { x: 0.3, y: 0.3 } });
Параметр key указывает на загруженное изображение 'block'. repeat: 107 создаёт 108 объектов (один основной + 107 повторений). setScale применяет ко всем объектам группы начальный масштаб 0.3, уменьшая их.
Затем мы выравниваем все дочерние объекты группы в сетку 12x9 с помощью статического метода Phaser.Actions.GridAlign. Это ключевой момент для получения ровного поля.
Phaser.Actions.GridAlign(blocks.getChildren(), {
width: 12,
height: 9,
cellWidth: 60,
cellHeight: 60,
x: 40,
y: 30
});
Параметры width и height задают размер сетки (12 колонок, 9 строк). cellWidth и cellHeight определяют расстояние между центрами объектов. `xиy` — это координаты верхнего левого угла всей сетки. Метод автоматически расставляет все 108 спрайтов в указанную сетку.
Анимация волны с помощью твинов
Чтобы создать волнообразный эффект, мы применяем твин к каждому спрайту в группе, но с разной задержкой (delay). Переменная `i` служит счётчиком для расчёта этой задержки, обнуляясь в конце каждой строки.
let i = 0;
blocks.children.forEach(child => {
this.tweens.add({
targets: child,
scale: 1,
ease: 'sine.inout',
duration: 300,
delay: i * 50,
repeat: -1,
yoyo: true
});
i++;
if (i % 12 === 0)
{
i = 0;
}
});
Конфигурация твина:
- targets: объект анимации (текущий спрайт child).
- scale: 1: конечное значение масштаба (увеличение с 0.3 до 1).
- ease: 'sine.inout': функция плавности, обеспечивающая мягкое ускорение и замедление.
- duration: 300: длительность одного цикла анимации в миллисекундах.
- delay: i * 50: задержка старта. Каждый следующий спрайт в строке начинает анимацию на 50мс позже предыдущего, создавая волну.
- repeat: -1: бесконечное повторение.
- yoyo: true: после завершения анимация проигрывается в обратном порядке, создавая эффект "пульсации".
Настройка игры (конфигурация)
Сцена инкапсулирует всю логику. Чтобы игра запустилась, необходимо создать экземпляр Phaser.Game и передать ему конфигурационный объект.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
type определяет рендерер (WebGL или Canvas), width и height — размеры игрового холста. backgroundColor задаёт цвет фона до загрузки ассетов. parent — это ID HTML-элемента, в который будет встроен canvas. scene указывает на класс нашей сцены.
Что попробовать дальше
Комбинируя Group, Phaser.Actions.GridAlign и Tweens, мы создали сложный визуальный эффект с минимальным количеством кода. Для экспериментов попробуйте изменить параметры сетки (например, width: 18, height: 6), тип функции плавности (ease) на 'bounce.out' или 'power2', или анимируйте другие свойства, например alpha (прозрачность) или angle. Можно создать две волны, идущие навстречу друг другу, изменив логику расчёта задержки. Этот паттерн — отличная основа для создания анимированных меню, фонов стратегических карт или эффектов мощности в аркадных играх.
