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

Этот пример демонстрирует мощь Phaser для создания визуальных эффектов, характерных для демосцены. Мы разберем, как с помощью одной текстуры, группы спрайтов, тонирования и цепочек анимаций создать гипнотический движущийся 'ковер'. Этот подход полезен для создания фоновых эффектов, переходов или просто для изучения работы с группами (`Group`) и менеджером анимаций (`Tweens`).

Версия 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.image('raster', 'assets/demoscene/raster-w-800x16.png');
        this.load.image('raster', 'assets/demoscene/raster-bw-800x16.png');
    }

    create ()
    {
        const group = this.add.group();

        group.createMultiple({ key: 'raster', repeat: 64 });

        const hsv = Phaser.Display.Color.HSVColorWheel();

        let i = 0;

        const _this = this;

        group.children.forEach(child =>
        {

            child.x = 500;
            child.y = 100;
            child.depth = 64 - i;
            child.scaleX = 0.6;

            // child.setBlendMode(Phaser.BlendModes.ADD);

            child.setTint(hsv[i * 4].color);

            i++;

            _this.tweens.add({
                targets: child,
                props: {
                    x: { value: 300, duration: 700 },
                    y: { value: 500, duration: 2500 },
                    scaleX: { value: Math.min(0.1, child.depth / 64), duration: 4000, hold: 2000, delay: 2000 }
                },
                yoyo: true,
                repeat: -1,
                ease: 'Sine.easeInOut',
                delay: 38 * i
            });

        });
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};

const game = new Phaser.Game(config);

Подготовка ресурсов и создание группы

В методе preload загружается одна текстурная полоса raster. Ключевой объект здесь — группа (Group). Группа позволяет управлять множеством игровых объектов как единым целым, что идеально для повторяющихся элементов.

const group = this.add.group();
group.createMultiple({ key: 'raster', repeat: 64 });

Вызов createMultiple создает 65 спрайтов (1 оригинальный + 64 повторения), используя загруженное изображение 'raster' в качестве текстуры. Все они автоматически добавляются в группу group.

Настройка спрайтов: позиция, глубина и цвет

Далее в цикле forEach мы настраиваем каждый созданный спрайт (child). Изначально все спрайты позиционируются в одной точке (x: 500, y: 100).

child.depth = 64 - i;
child.scaleX = 0.6;
child.setTint(hsv[i * 4].color);

- depth определяет порядок отрисовки. Спрайты с большим значением будут рисоваться поверх других. Здесь он убывает, создавая основу для перспективы. - scaleX сжимает спрайт по горизонтали, превращая квадратную текстуру в вертикальную полосу. - setTint применяет цвет из заранее сгенерированной палитры hsv. Phaser.Display.Color.HSVColorWheel() создает массив из 360 цветов, что позволяет легко получить плавный градиент по индексу `i`.

Создание цепочек анимаций с помощью Tweens

Сердце эффекта — система твинов. Для каждого спрайта создается цепочка анимаций, управляемая одним твин-менеджером.

_this.tweens.add({
    targets: child,
    props: {
        x: { value: 300, duration: 700 },
        y: { value: 500, duration: 2500 },
        scaleX: { value: Math.min(0.1, child.depth / 64), duration: 4000, hold: 2000, delay: 2000 }
    },
    yoyo: true,
    repeat: -1,
    ease: 'Sine.easeInOut',
    delay: 38 * i
});

- targets: объект для анимации. - props: свойства для изменения. Каждое свойство (`x,y,scaleX) имеет свои параметры: конечноеvalue, длительностьduration, задержкуdelayи время удержанияhold`. - yoyo: true заставляет анимацию проигрываться в обратном порядке после завершения. - repeat: -1 устанавливает бесконечное повторение. - ease: функция плавности 'Sine.easeInOut' для мягкого ускорения и замедления. - delay: задержка старта анимации для каждого спрайта, увеличивающаяся с индексом `i`. Это создает волнообразный, последовательный эффект движения.

Сборка сцены и конфигурация игры

Класс Example расширяет Phaser.Scene. Вся логика содержится в стандартных методах сцены preload и create.

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Example
};
const game = new Phaser.Game(config);

Объект config передается в конструктор Phaser.Game, запуская игровой цикл. Параметр scene указывает на наш класс сцены, который будет инстанциирован автоматически.

Что попробовать дальше

Пример показывает, как из минимальных элементов — одной текстуры и грамотного кода — рождается сложный визуальный паттерн. Для экспериментов попробуйте: изменить палитру (использовать RGB вместо HSV), добавить вращение через angle, применить другой бленд-мод (раскомментировать setBlendMode), или варьировать формулу delay для создания иных волновых эффектов.