О чем этот пример
Демо-сцены — это отличный способ создать визуально привлекательные эффекты с минимальным кодом. В этом примере мы разберем, как с помощью группы спрайтов (Group) и твинов (Tweens) в Phaser создать гипнотическую вертикальную волну из цветных полос. Этот подход полезен для создания фоновых анимаций, эффектов меню или визуализации данных в играх, демонстрируя мощь встроенной системы анимаций и управления множеством объектов.
Версия 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('raster', 'assets/phaser3/bars.png', { frameWidth: 46, frameHeight: 2 });
}
create ()
{
const group = this.add.group();
const x = 200;
let y = 0;
let frame = 0;
for (let i = 0; i < 180; i++)
{
const bar = group.create(x, y, 'raster', frame);
bar.setOrigin(0);
bar.displayHeight = 600 - y;
y += 3;
frame++;
if (frame === 9)
{
frame = 0;
}
}
this.tweens.add({
targets: group.getChildren(),
x: 600,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut',
duration: 1500,
delay: function (target, key, value, targetIndex)
{
return targetIndex * 30;
}
});
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Загрузка ресурсов и подготовка
В методе preload мы загружаем спрайтшит — изображение, содержащее несколько кадров анимации в одной текстуре. Это эффективный способ хранить похожие графические элементы.
this.load.spritesheet('raster', 'assets/phaser3/bars.png', { frameWidth: 46, frameHeight: 2 });
Здесь 'raster' — это ключ ресурса. Второй аргумент — путь к файлу. Третий аргумент — объект конфигурации, где frameWidth и frameHeight задают размер одного кадра в пикселях. Наш спрайтшит состоит из 9 вертикальных полос разного цвета, каждая шириной 46 пикселей и высотой 2 пикселя.
Создание группы и размещение полос
В методе create мы создаем визуальный эффект. Сначала инициализируется группа (Group) — специальный контейнер Phaser для управления коллекцией игровых объектов.
const group = this.add.group();
Затем в цикле создаются 180 спрайтов-полос, которые добавляются в эту группу. Ключевые моменты настройки каждого спрайта:
const bar = group.create(x, y, 'raster', frame);
bar.setOrigin(0);
bar.displayHeight = 600 - y;
1. group.create(x, y, 'raster', frame) — создает спрайт из текстуры 'raster' с конкретным кадром frame и сразу добавляет его в группу. Координата `xфиксирована,y` увеличивается с каждой итерацией, выстраивая полосы вертикально.
2. bar.setOrigin(0) — устанавливает точку привязки (origin) спрайта в его левый верхний угол. Это нужно, чтобы изменение высоты происходило вниз от точки создания, а не в обе стороны.
3. bar.displayHeight = 600 - y — динамически задает высоту спрайта. Чем ниже создается полоса (больше `y`), тем короче она будет. Это создает диагональный скос для всей конструкции.
4. Переменная frame циклически меняется от 0 до 8, обеспечивая смену цвета полос по порядку.
Анимация волны с помощью Tweens
Сердце эффекта — анимация с использованием системы твинов (Tweens). Твин плавно изменяет свойства объектов с течением времени.
this.tweens.add({
targets: group.getChildren(),
x: 600,
yoyo: true,
repeat: -1,
ease: 'Sine.easeInOut',
duration: 1500,
delay: function (target, key, value, targetIndex) {
return targetIndex * 30;
}
});
Разберем конфигурацию:
- targets: group.getChildren() — цель анимации: массив всех спрайтов в группе.
- x: 600 — конечное значение свойства `x` (горизонтальное движение).
- yoyo: true — после завершения анимации до конца, она проигрывается в обратном порядке.
- repeat: -1 — анимация повторяется бесконечно.
- ease: 'Sine.easeInOut' — функция плавности (easing), которая делает движение медленным в начале и в конце, создавая волнообразное ощущение.
- duration: 1500 — длительность одного цикла анимации (вперед или назад) в миллисекундах.
- delay: function (targetIndex) { return targetIndex * 30; } — ключевая настройка для волны. Она задает задержку старта анимации для каждого спрайта в зависимости от его индекса в массиве. Каждая следующая полоса начинает движение на 30 мс позже предыдущей, что и создает последовательную волну.
Конфигурация игры и запуск
Финальный шаг — создание экземпляра игры с необходимой конфигурацией.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Особенность этой конфигурации — флаг pixelArt: true. Когда он установлен, Phaser автоматически отключает сглаживание (anti-aliasing) при масштабировании текстур. Это критически важно для сохранения четкого вида пиксельной графики, к которой относится наш спрайтшит с тонкими полосками высотой 2 пикселя. Без этого флага полосы могли бы выглядеть размытыми.
Что попробовать дальше
Этот пример — отличная демонстрация принципа композиции в Phaser: простая геометрия, умноженная на количество объектов и управляемая твинами, рождает сложный визуальный паттерн. Для экспериментов попробуйте изменить функцию в delay на targetIndex * 10 для более резкой волны или Math.sin(targetIndex) * 100 для сложного паттерна. Замените ease на 'Cubic.easeOut' или 'Back.easeOut'. Измените свойство анимации с `xнаangleилиscaleY`, чтобы получить совершенно другие эффекты вращения или пульсации.
