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

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

Версия 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('explosion', 'assets/particles/explosion.png', 'assets/particles/explosion.json');
    }

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

        //  Setting { min: x, max: y } will pick a random value between min and max
        //  Setting { start: x, end: y } will ease between start and end

        particles.createEmitter({
            frame: [ 'smoke-puff', 'cloud', 'smoke-puff' ],
            angle: { min: 240, max: 300 },
            speed: { min: 200, max: 300 },
            quantity: 6,
            lifespan: 2000,
            alpha: { start: 1, end: 0 },
            scale: { start: 1.5, end: 0.5 },
            on: false
        });

        particles.createEmitter({
            frame: 'red',
            angle: { start: 0, end: 360, steps: 32 },
            lifespan: 1000,
            speed: 400,
            quantity: 32,
            scale: { start: 0.3, end: 0 },
            on: false
        });

        particles.createEmitter({
            frame: 'stone',
            angle: { min: 240, max: 300 },
            speed: { min: 400, max: 600 },
            quantity: { min: 2, max: 10 },
            lifespan: 4000,
            alpha: { start: 1, end: 0 },
            scale: { min: 0.05, max: 0.4 },
            rotate: { start: 0, end: 360, ease: 'Back.easeOut' },
            gravityY: 800,
            on: false
        });

        particles.createEmitter({
            frame: 'muzzleflash2',
            lifespan: 200,
            scale: { start: 2, end: 0 },
            rotate: { start: 0, end: 180 },
            on: false
        });

        this.input.on('pointerdown', pointer =>
        {

            particles.emitParticleAt(pointer.x, pointer.y);

        });
    }
}

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

const game = new Phaser.Game(config);

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

Для работы с частицами в Phaser часто используют атласы текстур — это один файл изображения и JSON-файл с координатами каждого кадра (frame). Это эффективнее, чем загружать множество отдельных картинок.

В методе preload мы загружаем такой атлас под ключом 'explosion'. Код загружает изображение explosion.png и данные о кадрах из explosion.json.

this.load.atlas('explosion', 'assets/particles/explosion.png', 'assets/particles/explosion.json');

Создание менеджера частиц и эмиттеров

В методе create мы создаем систему частиц, которая будет управлять всеми эмиттерами. Затем мы создаем четыре разных эмиттера с уникальными параметрами. Ключевой параметр on: false означает, что эмиттеры не испускают частицы автоматически. Они будут активированы позже по команде.

const particles = this.add.particles('explosion');

Каждый вызов particles.createEmitter() создает новый эмиттер с заданным конфигом. Обратите внимание на гибкость настройки свойств: - frame: определяет текстуру (спрайт) для частиц. Можно указать один кадр или массив кадров для случайного выбора. - angle: направление вылета частиц. Можно задать случайный диапазон (min/max) или равномерное распределение по шагам (steps). - speed, lifespan, quantity, scale, alpha, rotate: основные свойства, управляющие поведением и внешним видом. - gravityY: имитация гравитации, заставляет частицы падать. - ease: функция плавности (easing) для анимации свойств между start и end.

particles.createEmitter({
    frame: [ 'smoke-puff', 'cloud', 'smoke-puff' ],
    angle: { min: 240, max: 300 },
    speed: { min: 200, max: 300 },
    quantity: 6,
    lifespan: 2000,
    alpha: { start: 1, end: 0 },
    scale: { start: 1.5, end: 0.5 },
    on: false
});

Активация всех эмиттеров по клику

Вся магия происходит в обработчике события pointerdown. Когда пользователь кликает по холсту, мы вызываем метод emitParticleAt у менеджера частиц particles.

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

this.input.on('pointerdown', pointer =>
{
    particles.emitParticleAt(pointer.x, pointer.y);
});

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

Код завершается стандартной для Phaser 3 конфигурацией игры. Мы указываем тип рендерера (WEBGL для лучшей производительности частиц), размеры холста, цвет фона, ID родительского HTML-элемента и класс нашей сцены Example.

Затем создается экземпляр игры new Phaser.Game(config), который инициализирует все системы и запускает нашу сцену.

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

const game = new Phaser.Game(config);

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

Вы освоили базовый паттерн создания сложных частичных эффектов в Phaser 3: создание менеджера, настройка нескольких отключенных эмиттеров и их одновременная активация в нужной точке. Это основа для эффектов выстрелов, взрывов, подобранных бонусов или следов. Для экспериментов попробуйте: 1. Изменить параметры эмиттеров (скорость, гравитацию, количество) для получения совершенно другого визуального стиля. 2. Привязать вызов emitParticleAt не к клику, а к столкновению (collide) игровых объектов. 3. Создавать разные менеджеры частиц (this.add.particles) для разных типов эффектов и управлять ими независимо.