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

Эмиттеры частиц в Phaser могут превратить статичные эффекты в динамичные визуальные системы. Встроенный компонент `EdgeZone` позволяет задавать точную геометрию для испускания частиц, но настоящая мощь раскрывается при использовании пользовательских источников. Эта статья покажет, как создавать собственные математические формы для эмиттеров и динамически изменять их в реальном времени, открывая путь к уникальным эффектам, таким как анимированные ауры, волшебные следы и сложные геометрические паттерны.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    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 ()
    {
        const particles = this.add.particles('flares');

        let k = 3;

        const rose = {
            getPoints: function (quantity, stepRate)
            {
                if (!stepRate)
                {
                    stepRate = Phaser.Math.PI2 / quantity;
                }

                const input = Phaser.Utils.Array.NumberArrayStep(0, Phaser.Math.PI2, stepRate);

                const output = new Array(input.length);

                for (let i = 0; i < input.length; i++)
                {
                    const angle = input[i];

                    output[i] = new Phaser.Math.Vector2().setToPolar(angle, 200 * Math.cos(k * angle));
                }

                return output;
            }
        };

        const emitter = particles.createEmitter({
            frame: { frames: [ 'green', 'blue' ], cycle: true },
            x: 400,
            y: 300,
            scale: { start: 0.5, end: 0 },
            blendMode: 'ADD',
            emitZone: { type: 'edge', source: rose, quantity: 360 }
        });

        this.input.on('pointerup', () =>
        {
            k++;

            emitter.emitZone.updateSource();
        });
    }
}

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

const game = new Phaser.Game(config);

Основа: EdgeZone и пользовательский источник

В Phaser для создания эмиттера частиц используется this.add.particles(). Ключевую роль в позиционировании частиц играет конфигурация emitZone. При указании type: 'edge' мы говорим системе, что частицы будут появляться вдоль линии или кривой.

Параметр source определяет форму этой кривой. Это может быть встроенный объект геометрии Phaser (например, круг или прямоугольник) или пользовательский объект с обязательным методом getPoints(quantity, stepRate). Этот метод должен возвращать массив объектов Phaser.Math.Vector2, определяющих точки для испускания частиц.

emitZone: {
    type: 'edge',
    source: customShapeObject,
    quantity: 360
}

Математика формы: полярные координаты и "розы"

В примере создается фигура, известная как "роза" или полярная роза. Её форма задается полярным уравнением: радиус зависит от угла.

Метод getPoints пользовательского объекта rose делает следующее: 1. Создает массив углов от 0 до 2π (полный круг) с заданным шагом stepRate. 2. Для каждого угла вычисляет радиус по формуле r = 200 * Math.cos(k * angle). Параметр `k` определяет количество "лепестков". 3. Преобразует полярные координаты (угол, радиус) в декартовы (x, y) с помощью Phaser.Math.Vector2().setToPolar().

const rose = {
    getPoints: function (quantity, stepRate) {
        // ... создание массива углов (input) ...
        const output = new Array(input.length);
        for (let i = 0; i < input.length; i++) {
            const angle = input[i];
            // Формула полярной розы
            output[i] = new Phaser.Math.Vector2().setToPolar(angle, 200 * Math.cos(k * angle));
        }
        return output;
    }
};

Сборка эмиттера: настройка визуала

Эмиттер конфигурируется с нашим пользовательским источником rose. Частицы берутся из атласа 'flares', и для создания цветового разнообразия используется анимация кадров frame. Частицы уменьшаются от размера 0.5 до 0 (scale) и используют аддитивное смешивание (blendMode: 'ADD'), что делает их яркими и подходящими для световых эффектов.

const emitter = particles.createEmitter({
    frame: { frames: [ 'green', 'blue' ], cycle: true },
    x: 400,
    y: 300,
    scale: { start: 0.5, end: 0 },
    blendMode: 'ADD',
    emitZone: { type: 'edge', source: rose, quantity: 360 }
});

Интерактивность: Обновление геометрии на лету

Самая интересная часть — динамическое изменение формы. По клику мыши увеличивается параметр `kв формуле розы. Чтобы эмиттер начал испускать частицы по новой форме, необходимо вызвать методemitZone.updateSource()`. Этот метод заставляет эмиттер пересчитать все точки источника заново. Новые частицы будут появляться уже на обновленной кривой, создавая живую, реагирующую на действия игрока анимацию.

this.input.on('pointerup', () => {
    k++; // Меняем форму
    emitter.emitZone.updateSource(); // Применяем изменения
});

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

Использование пользовательских источников для EdgeZone превращает эмиттеры частиц из простых эффектов в программируемые визуальные конструкторы. Вы можете экспериментировать: попробуйте заменить формулу розы на спираль (r = a * angle), лемнискату или фигуру Лиссажу. Источником может выступать не только математическая функция, но и заранее подготовленный массив точек, например, очертание спрайта или путь, пройденный игроком. Это открывает возможности для создания следов за заклинаниями, динамических границ силовых полей или частиц, выстраивающихся в логотип.