О чем этот пример

Демо-сцены — это отличный способ создать визуально привлекательные эффекты с минимальным кодом. В этом примере мы разберем, как с помощью группы спрайтов (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`, чтобы получить совершенно другие эффекты вращения или пульсации.