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

Визуальные эффекты оживляют игру, но статичные частицы быстро теряют интерес. В примере из баг-трекера Phaser (bugs/5847) показана мощная, но малоизвестная возможность: создание эмиттера частиц, который движется вместе с другим игровым объектом. Это открывает двери для создания эффектов шагающего персонажа, следа от двигателя, волшебной ауры, следующей за предметом, и многих других динамичных систем частиц. В этой статье мы разберем, как работает метод `startFollow()` и как настроить эмиттер для создания пошагового эффекта.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.55.2.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Demo extends Phaser.Scene
{
    constructor()
    {
        super();
    }

    preload()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.atlas('flares', 'assets/particles/flares.png', 'assets/particles/flares.json');
    }

    create()
    {
        let follow = this.add.rectangle(0, 100, 400, 20, 0xff0000);

        this.add.tween({
            targets: follow,
            duration: 10000,
            x: this.scale.width,
            yoyo: true,
            repeat: -1
        });

        var stepConfig = {
            frame: 'blue',
            x: { start: -160, end: 200, steps: 8 },
            y: 10,
            speedY: 200,
            lifespan: 4000,
            scale: 0.5,
            quantity: 8,
            frequency: 250,
        }

        this.add.particles('flares').createEmitter(stepConfig).startFollow(follow);
    }
}

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

const game = new Phaser.Game(config);

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

Вся работа происходит в стандартном классе сцены Phaser. Для хранения текстур частиц используется формат Atlas, который объединяет множество кадров в один файл изображения и отдельный JSON-файл с координатами.

preload()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.atlas('flares', 'assets/particles/flares.png', 'assets/particles/flares.json');
}

Метод preload загружает необходимые ресурсы. setBaseURL задает базовый путь для всех последующих загрузок. load.atlas загружает атлас с ключом 'flares', который будет использоваться для создания эмиттера.

Создание объекта-лидера и его анимации

Прежде чем заставить частицы следовать за чем-либо, нужно создать сам этот объект. В данном примере это простой красный прямоугольник, который будет непрерывно двигаться по экрану.

create()
{
    let follow = this.add.rectangle(0, 100, 400, 20, 0xff0000);

    this.add.tween({
        targets: follow,
        duration: 10000,
        x: this.scale.width,
        yoyo: true,
        repeat: -1
    });
}

Строка let follow = this.add.rectangle(...) создает прямоугольник (GameObject) в точке (0, 100) с шириной 400 и высотой 20 пикселей красного цвета. Далее для этого объекта создается твин (анимация). Он будет двигать прямоугольник от начальной позиции до правого края экрана (this.scale.width) за 10 секунд. Параметры yoyo: true и repeat: -1 заставляют анимацию проигрываться в обратном направлении по завершении и повторяться бесконечно.

Настройка эмиттера частиц с шаговым распределением

Сердце примера — конфигурация эмиттера. Здесь используется особое свойство steps для создания дискретного, «шагающего» эффекта.

var stepConfig = {
    frame: 'blue',
    x: { start: -160, end: 200, steps: 8 },
    y: 10,
    speedY: 200,
    lifespan: 4000,
    scale: 0.5,
    quantity: 8,
    frequency: 250,
}

Ключевой параметр — x: { start: -160, end: 200, steps: 8 }. Он определяет не плавный разброс, а 8 конкретных точек по оси X (от -160 до 200), в которых будут появляться частицы. Это создает эффект нескольких дискретных источников. frame: 'blue' задает кадр из атласа 'flares'. speedY: 200 — вертикальная скорость частиц. lifespan: 4000 — время жизни в миллисекундах. quantity: 8 и frequency: 250 означают, что каждые 250 мс будет испускаться по 8 частиц.

Создание эмиттера и привязка к объекту

Финальный шаг — создание системы частиц, эмиттера и его привязка к движущемуся прямоугольнику.

this.add.particles('flares').createEmitter(stepConfig).startFollow(follow);

1. this.add.particles('flares') создает менеджер (ParticleEmitterManager) для работы с частицами, используя загруженный атлас. 2. .createEmitter(stepConfig) на основе нашей конфигурации создает и возвращает конкретный эмиттер (ParticleEmitter). 3. .startFollow(follow) — это тот самый метод, который заставляет всю систему частиц (облако испускаемых частиц) следовать за целевым игровым объектом follow. Теперь источник частиц движется вместе с красным прямоугольником, создавая эффект шагающей линии огней.

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

Стандартная конфигурация игры Phaser 3, которая создает холст и запускает нашу сцену.

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

const game = new Phaser.Game(config);

Здесь задаются базовые параметры: автоматический выбор рендерера (Phaser.AUTO), идентификатор родительского DOM-элемента, размеры окна, черный фон и класс основной сцены.

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

Метод startFollow() — это простой, но эффективный способ оживить мир игры динамическими эффектами, привязанными к движению объектов. Использование шагового распределения (steps) для координат эмиттера добавляет контролируемую структуру в хаос частиц. Для экспериментов попробуйте: изменить форму и путь объекта-лидера (например, на круг, движущийся по синусоиде), комбинировать несколько эмиттеров с разными конфигурациями, следующих за одним объектом, или использовать stopFollow() для создания эффектов, которые остаются в мире после прохождения объекта (как пыль или следы).