О чем этот пример
Tween (или анимация переходов) — один из ключевых инструментов для создания плавных визуальных эффектов в играх. В этом примере мы разберем, как использовать систему твинов 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.image('bg', 'assets/pics/skull-and-bones.jpg');
this.load.image('block', 'assets/sprites/50x50-black.png');
}
create ()
{
this.add.image(400, 300, 'bg');
const blocks = this.add.group({ key: 'block', repeat: 191 });
Phaser.Actions.GridAlign(blocks.getChildren(), {
width: 16,
cellWidth: 50,
cellHeight: 50,
x: 0,
y: 0
});
var _this = this;
let i = 0;
blocks.children.forEach(child =>
{
this.tweens.add({
targets: child,
scaleX: 0,
scaleY: 0,
alpha: 0,
y: '+=64',
angle: 180,
ease: 'Power3',
duration: 1000,
yoyo: true,
delay: 1000 + (i * 100),
hold: 1500,
});
i++;
// Change the value 32 for different results
if (i % 16 === 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);
Подготовка сцены и загрузка ассетов
В методе preload мы загружаем два изображения: фоновую картинку (bg) и маленький черный спрайт (block), который станет нашим повторяющимся элементом. Важно использовать this.load.setBaseURL() для указания базового URL, чтобы пути к файлам были относительными.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('bg', 'assets/pics/skull-and-bones.jpg');
this.load.image('block', 'assets/sprites/50x50-black.png');
}
Создание группы и выравнивание объектов по сетке
В методе create сначала добавляется фоновое изображение. Затем создается группа (Group) — специальный контейнер Phaser для управления коллекцией похожих объектов. Параметр { key: 'block', repeat: 191 } указывает, что группа должна создать 192 спрайта (1 исходный + 191 повторение) на основе изображения block.
Далее, Phaser.Actions.GridAlign используется для автоматического расположения всех детей группы в аккуратную сетку. Параметры задают ширину сетки в 16 столбцов, размер каждой ячейки 50x50 пикселей и начальную позицию (0, 0).
const blocks = this.add.group({ key: 'block', repeat: 191 });
Phaser.Actions.GridAlign(blocks.getChildren(), {
width: 16,
cellWidth: 50,
cellHeight: 50,
x: 0,
y: 0
});
Настройка каскадных твинов для каждого блока
Сердце примера — цикл по всем блокам в группе и создание для каждого отдельного твина. Для отслеживания задержки используется переменная `i`.
Конфигурационный объект твина определяет его поведение:
* targets: объект, к которому применяется анимация (в нашем случае — child, текущий блок).
* scaleX, scaleY, alpha: целевые значения. Блок уменьшится до нуля и станет полностью прозрачным.
* y: '+=64': блок сместится вниз на 64 пикселя от своей текущей позиции.
* angle: 180: блок повернется на 180 градусов.
* ease: функция плавности 'Power3' обеспечивает более естественное движение с ускорением и замедлением.
* duration: длительность одной фазы анимации (до достижения целевых значений) — 1000 мс.
* yoyo: true: после завершения анимация воспроизведется в обратном порядке, возвращая блок в исходное состояние.
* delay: ключевой параметр. Задержка перед началом анимации для каждого блока рассчитывается как 1000 + (i * 100). Это создает эффект "волны", где каждый следующий блок в строке начинает анимацию на 100 мс позже предыдущего.
* hold: пауза (1500 мс) между завершением первой фазы анимации и началом фазы yoyo.
this.tweens.add({
targets: child,
scaleX: 0,
scaleY: 0,
alpha: 0,
y: '+=64',
angle: 180,
ease: 'Power3',
duration: 1000,
yoyo: true,
delay: 1000 + (i * 100),
hold: 1500,
});
Сброс счетчика для формирования рядов
После обработки каждого блока индекс `iувеличивается. Условиеif (i % 16 === 0)сбрасывает счетчикi` обратно в 0 каждый раз после обработки 16 блоков. Поскольку сетка имеет ширину 16 столбцов, это означает, что сброс происходит в конце каждого ряда. В результате анимация запускается не единой диагональной линией по всей сетке, а построчно, создавая характерный "шахматный" или "волновой" каскад сверху вниз.
i++;
// Change the value 32 for different results
if (i % 16 === 0)
{
i = 0;
}
Комментарий в коде намекает: изменение делителя с 16 на другое число (например, 32) кардинально изменит паттерн анимации, так как изменится момент сброса счетчика.
Что попробовать дальше
Этот пример наглядно демонстрирует мощность и гибкость системы твинов Phaser в сочетании с группами и действиями (Actions). Вы можете экспериментировать: измените свойства анимации (например, `xвместоy, другие значенияangleилиscale), попробуйте другую функциюease(например,Bounce.out), варьируйте параметрыdelayиhold` или измените делитель в условии сброса счетчика для создания совершенно новых визуальных паттернов и ритмов анимации.
