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

Создание статичных эффектов частиц — это лишь первый шаг. Настоящая магия начинается, когда эмиттер оживает и движется по сцене, создавая сложные динамические визуальные паттерны. В этой статье мы разберем, как легко анимировать систему частиц, используя встроенный в Phaser 3 менеджер `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('bg', 'assets/tweens/sky.png');
        this.load.atlas('match3', 'assets/atlas/match3.png', 'assets/atlas/match3.json');
    }

    create ()
    {
        this.add.image(400, 300, 'bg');

        const emitter = this.add.particles(100, 200, 'match3', {
            frame: 'Match3_Icon_30',
            speed: 120,
            lifespan: 2000,
            scale: 0.3,
            alpha: { start: 1, end: 0 }
        });

        this.tweens.add({
            targets: emitter,
            x: 700,
            duration: 2500,
            ease: 'sine.inout',
            yoyo: true,
            repeat: -1
        });

        this.tweens.add({
            targets: emitter,
            y: 400,
            duration: 1000,
            ease: 'sine.inout',
            yoyo: true,
            repeat: -1
        });
    }
}

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

const game = new Phaser.Game(config);

Подготовка сцены и создание эмиттера

Как и в большинстве примеров Phaser, работа начинается с методов preload и create. В preload мы загружаем необходимые ассеты: фоновое изображение и атлас с кадрами для частиц.

Затем, в create, мы сначала добавляем фон, чтобы визуально отделить эффект. Ключевой момент — создание самого эмиттера частиц с помощью метода this.add.particles().

const emitter = this.add.particles(100, 200, 'match3', {
    frame: 'Match3_Icon_30',
    speed: 120,
    lifespan: 2000,
    scale: 0.3,
    alpha: { start: 1, end: 0 }
});

Этот код создает эмиттер в точке (100, 200). В качестве текстуры используется атлас 'match3', а конкретная частица берется из кадра 'Match3_Icon_30'. Частицы будут вылетать со скоростью 120 пикселей в секунду, жить 2000 миллисекунд, иметь масштаб 0.3 и плавно исчезать от полной непрозрачности к полной прозрачности. Важно: эмиттер сам является игровым объектом (Game Object), что позволяет применять к нему различные трансформации.

Анимация по горизонтали с помощью Tween

Phaser предоставляет мощную систему твинов для плавной анимации свойств объектов. Мы можем анимировать свойства самого эмиттера, такие как его позиция `xиy`. Первый твин отвечает за движение по горизонтали.

this.tweens.add({
    targets: emitter, // Цель анимации — наш эмиттер
    x: 700,          // Конечная координата X
    duration: 2500,  // Длительность анимации в мс
    ease: 'sine.inout', // Функция плавности
    yoyo: true,      // Проиграть анимацию в обратном порядке
    repeat: -1       // Бесконечное повторение
});

Здесь мы говорим системе твинов: "Анимируй свойство `xобъектаemitterот его текущего значения (100) до 700 за 2500 миллисекунд, используя плавную S-образную функцию'sine.inout'`. После завершения проиграй анимацию в обратную сторону (yoyo) и повторяй это бесконечно (repeat: -1)". В результате эмиттер начинает плавно "плавать" слева направо и обратно.

Анимация по вертикали и композиция движения

Сила подхода в том, что мы можем независимо управлять разными свойствами, создавая сложную результирующую траекторию. Второй твин управляет движением по вертикали.

this.tweens.add({
    targets: emitter,
    y: 400,          // Конечная координата Y
    duration: 1000,  // Более короткая длительность
    ease: 'sine.inout',
    yoyo: true,
    repeat: -1
});

Этот твин анимирует свойство `y` эмиттера от 200 до 400 за 1 секунду, также в режиме йо-йо. Обратите внимание, что длительность (1000 мс) отличается от длительности горизонтального движения (2500 мс). Это означает, что эмиттер будет двигаться по вертикали в 2.5 раза быстрее, чем по горизонтали. Два независимых, но одновременно работающих твина создают сложное и визуально интересное движение по диагональной, постоянно меняющейся траектории. Все частицы продолжают излучаться из текущей позиции движущегося эмиттера, формируя извилистый след.

Конфигурация игры и запуск

Код завершается стандартной для Phaser 3 конфигурацией игры, которая указывает движку, какую сцену использовать и с какими базовыми параметрами.

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#000',
    parent: 'phaser-example',
    scene: Example // Наша класс-сцена
};

const game = new Phaser.Game(config);

Ключевое поле scene указывает на наш класс Example. Фон (backgroundColor) установлен черным, но в данном примере он перекрывается фоновым изображением 'bg', загруженным в сцене. Параметры width и height задают размер игрового холста.

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

Комбинируя систему частиц и твины, вы получаете мощный инструмент для создания динамических фонов, живых эффектов вокруг персонажей или сложных визуализаций. Для экспериментов попробуйте: изменить функцию плавности (ease) на 'bounce.out' или 'expo.in'; анимировать другие свойства эмиттера, например angle или scale; использовать несколько эмиттеров с разными текстурами и твинами для создания многослойного эффекта; привязать эмиттер к спрайту игрока, чтобы создавать постоянный след.