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

Система частиц — мощный инструмент для создания спецэффектов в играх, от огня и магии до взрывов и погоды. В Phaser 3 есть несколько способов настройки эмиттера частиц, и выбор правильного метода влияет на читаемость и производительность вашего кода. В этой статье мы разберем, как создавать эмиттеры, используя конфигурационный объект — самый лаконичный и эффективный подход, а также рассмотрим альтернативные методы для полного понимания API.

Версия 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');

        //  Create an emitter by passing in a config object directly to the Particle Manager

        const emitter = particles.createEmitter({
            frame: [ 'red', 'blue', 'green', 'yellow' ],
            x: 400,
            y: 300,
            speed: 200,
            lifespan: 3000,
            blendMode: 'ADD'
        });

        //  You can also call 'fromJSON' with the same config object:

        /*
        var emitter = particles.createEmitter();

        emitter.fromJSON({
            frame: [ 'red', 'blue', 'green', 'yellow' ],
            x: 400,
            y: 300,
            speed: 200,
            lifespan: 3000,
            blendMode: 'ADD'
        });
        */

        //  Both the above are the same as doing the following:
        //  (except using a config object is faster and more efficient)

        /*
        var emitter = particles.createEmitter();

        emitter.setFrame([ 'red', 'blue', 'green', 'yellow' ]);
        emitter.setPosition(400, 300);
        emitter.setSpeed(200);
        emitter.setLifespan(3000);
        emitter.setBlendMode('ADD');
        */
    }
}

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

const game = new Phaser.Game(config);

Загрузка атласа частиц

Перед созданием эмиттера необходимо загрузить текстуры для частиц. В Phaser для этого часто используют атласы — один изображение-спрайтшит и JSON-файл с координатами каждого кадра.

В методе preload мы указываем базовый URL для загрузки и загружаем атлас с ключом 'flares'. Этот атлас содержит несколько разноцветных вспышек ('red', 'blue' и т.д.).

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 мы создаем систему частиц для сцены. Объект particles — это фабрика и менеджер для эмиттеров.

Затем мы создаем эмиттер, передавая конфигурационный объект прямо в метод particles.createEmitter(). Это самый прямой способ.

Ключевые параметры конфига: - frame: массив имен кадров из атласа, которые будут использоваться как текстуры частиц. - `x,y`: начальная позиция эмиттера в мире. - speed: начальная скорость движения частиц (в пикселях в секунду). - lifespan: время жизни частицы в миллисекундах. - blendMode: режим наложения, 'ADD' дает яркий, светящийся эффект.

create ()
{
    const particles = this.add.particles('flares');

    const emitter = particles.createEmitter({
        frame: [ 'red', 'blue', 'green', 'yellow' ],
        x: 400,
        y: 300,
        speed: 200,
        lifespan: 3000,
        blendMode: 'ADD'
    });
}

Альтернативный метод: fromJSON

Иногда нужно создать эмиттер заранее, а настроить его позже. Для этого можно сначала создать "пустой" эмиттер, а затем применить к нему конфиг с помощью метода fromJSON().

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

// Альтернативный подход
var emitter = particles.createEmitter();
emitter.fromJSON({
    frame: [ 'red', 'blue', 'green', 'yellow' ],
    x: 400,
    y: 300,
    speed: 200,
    lifespan: 3000,
    blendMode: 'ADD'
});

Пошаговая настройка через сеттеры

Под капотом оба предыдущих метода используют набор отдельных сеттер-функций. Вы можете вызывать их вручную, что дает максимальный контроль над процессом.

Однако этот подход менее эффективен, так как каждое свойство устанавливается отдельным вызовом, что может привести к лишним перерасчетам. Используйте его, если нужно менять свойства по одному уже после создания (например, в реальном времени).

// Базовый, но менее эффективный способ
var emitter = particles.createEmitter();
emitter.setFrame([ 'red', 'blue', 'green', 'yellow' ]);
emitter.setPosition(400, 300);
emitter.setSpeed(200);
emitter.setLifespan(3000);
emitter.setBlendMode('ADD');

Настройка сцены и запуск игры

Весь пример обернут в стандартную конфигурацию игры Phaser. Мы указываем использование WebGL, размеры холста, цвет фона и класс нашей сцены Example.

Конструктор Phaser.Game запускает игровой цикл с переданной конфигурацией.

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

const game = new Phaser.Game(config);

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

Использование конфигурационного объекта при создании ParticleEmitter — это предпочтительный метод в Phaser 3. Он лаконичен, производителен и улучшает читаемость кода. Для экспериментов попробуйте: 1. Анимировать позицию эмиттера, привязав его к курсору мыши (emitter.setPosition(pointer.x, pointer.y)). 2. Поиграть с другими параметрами конфига, такими как scale, alpha, gravityY или frequency. 3. Создать несколько эмиттеров с разными конфигами для составных эффектов (например, дым + искры).