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

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

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

    create ()
    {
        this.add.particles('megaset', [
            {
                frame: 'red_ball',
                x: 400,
                y: 590,
                angle: { min: 180, max: 360 },
                speed: 200,
                gravityY: -350,
                lifespan: 3000,
                quantity: 4,
                scale: { min: 0.1, max: 1 }
            },
            {
                frame: 'yellow_ball',
                x: 400,
                y: 590,
                angle: { min: 180, max: 360 },
                speed: 300,
                gravityY: -350,
                lifespan: 3000,
                quantity: 4,
                scale: { min: 0.1, max: 1 }
            },
            {
                frame: 'blue_ball',
                x: 400,
                y: 590,
                angle: { min: 180, max: 360 },
                speed: 400,
                gravityY: -350,
                lifespan: 3000,
                quantity: 4,
                scale: { min: 0.1, max: 1 }
            }
        ]);
    }
}

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 мы загружаем атлас с именем 'megaset'. Базовый URL задаётся для удобства, чтобы не указывать полные пути к каждому файлу.

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

Создание группы эмиттеров: принцип композиции

Ключевой метод this.add.particles() создаёт не один, а сразу несколько эмиттеров, объединённых в один управляемый контейнер (ParticleEmitterManager). В качестве параметров он принимает ключ текстуры (или атласа) и массив конфигурационных объектов. Каждый объект в массиве описывает свой собственный эмиттер.

Это мощный паттерн, позволяющий создать сложный составной эффект, например, взрыв с искрами, дымом и обломками, используя один вызов API.

this.add.particles('megaset', [
    // ... конфигурации эмиттеров
]);

Декомпозиция конфигурации: красный слой

Рассмотрим параметры первого эмиттера, испускающего красные шары. Каждая настройка отвечает за конкретное свойство частиц.

- frame: задаёт конкретный кадр из атласа 'megaset', который будет использован как текстура частицы. В нашем случае это 'red_ball'. - `xиy`: координаты точки испускания (эмиттера) на сцене. Здесь она расположена внизу, по центру по горизонтали. - angle: определяет начальный угол вылета частицы в градусах. Значение { min: 180, max: 360 } означает, что частицы будут вылетать вверх, в диапазоне от прямой вертикали вверх (180°) до вертикали вниз (360°, что равно 0°). - speed: начальная скорость движения частицы в пикселях в секунду. - gravityY: сила гравитации, применяемая по оси Y. Отрицательное значение (-350) означает, что сила направлена вверх, противодействуя начальному импульсу и создавая дугообразную траекторию. - lifespan: время жизни частицы в миллисекундах. - quantity: количество частиц, испускаемых за один выброс. - scale: начальный масштаб частицы. Случайное значение в диапазоне от 0.1 до 1 создаёт ощущение разнообразия и глубины.

{
    frame: 'red_ball',
    x: 400,
    y: 590,
    angle: { min: 180, max: 360 },
    speed: 200,
    gravityY: -350,
    lifespan: 3000,
    quantity: 4,
    scale: { min: 0.1, max: 1 }
}

Создание вариаций: синий и жёлтый слои

Второй и третий эмиттеры в массиве создают жёлтые и синие шары соответственно. Их конфигурации идентичны красным, за исключением двух ключевых параметров: frame (для текстуры) и speed.

Изменение speed для каждого цвета — это простой, но эффективный способ создать иллюзию каскада или «фонтана»: шары с разной скоростью будут достигать разной высоты и иметь разную длину дуги, создавая объёмный и динамичный визуальный эффект из одной точки испускания.

// Жёлтые шары - средняя скорость
{
    frame: 'yellow_ball',
    ... // Остальные параметры как у красных
    speed: 300,
}

// Синие шары - наибольшая скорость
{
    frame: 'blue_ball',
    ... // Остальные параметры как у красных
    speed: 400,
}

Инициализация игры: конфигурация сцены

Весь эффект инкапсулирован в классе сцены Example. Для запуска игры необходимо создать экземпляр Phaser.Game, передав ему объект конфигурации. В этой конфигурации указывается тип рендерера, размеры холста, цвет фона, родительский HTML-элемент и класс основной сцены.

Использование Phaser.WEBGL предпочтительнее для систем частиц, так как WebGL обеспечивает аппаратное ускорение и значительно лучшую производительность при работе с большим количеством графических объектов.

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

const game = new Phaser.Game(config);

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

Вы разобрали, как с помощью одного вызова this.add.particles() создать сложный, многослойный эффект, управляя каждым слоем через отдельный конфигурационный объект. Это основа для построения любых визуальных систем: от дождя и снега до огненных штормов. **Идеи для экспериментов:** 1. Измените gravityY на положительное значение, чтобы частицы падали вниз, создав эффект водопада или дождя. 2. Добавьте параметр frequency в конфигурацию эмиттера, чтобы частицы испускались не один раз, а с заданным интервалом. 3. Поэкспериментируйте с другими свойствами, например alpha (прозрачность) или tint (оттенок), чтобы создать эффекты рассеивания или изменения цвета со временем. 4. Сделайте точку эмиттера (`x,y`) следующей за указателем мыши, создавая интерактивный фон.