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

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

Версия 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 shape1 = new Phaser.Geom.Circle(0, 0, 100);
        const shape2 = new Phaser.Geom.Ellipse(0, 0, 500, 150);
        const shape3 = new Phaser.Geom.Rectangle(-150, -150, 300, 300);
        const shape4 = new Phaser.Geom.Line(-150, -150, 150, 150);
        const shape5 = new Phaser.Geom.Triangle(0, -200, 200, 200, -200, 200);

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

        particles.createEmitter({
            frame: [ 'red', 'yellow', 'green', 'blue' ],
            x: 400, y: 300,
            speed: 90,
            lifespan: 3000,
            quantity: 48,
            frequency: 2000,
            delay: 1000,
            scale: { start: 0.4, end: 0 },
            blendMode: 'ADD',
            emitZone: { type: 'edge', source: shape5, quantity: 48 }
        });
    }
}

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

const game = new Phaser.Game(config);

Суть EdgeZone: Источник-фигура

Параметр emitZone в конфигурации эмиттера позволяет задать зону, из которой будут появляться частицы. Когда для type установлено значение 'edge', Phaser использует предоставленную геометрическую фигуру (source) как путь. Частицы рождаются не внутри фигуры, а строго на её границе (ребре). Это идеально для создания контурных эффектов.

Объект emitZone в примере выглядит так:

emitZone: { type: 'edge', source: shape5, quantity: 48 }

Здесь source: shape5 — это экземпляр Phaser.Geom.Triangle. Phaser возьмёт его периметр и будет размещать новые частицы в случайных точках вдоль этой линии. Параметр quantity в зоне определяет, сколько точек на границе фигуры будет сгенерировано за один вызов эмиттера. Важно: это значение связано с параметром quantity самого эмиттера.

Геометрический конструктор: Фигуры в Phaser

Прежде чем использовать фигуру как EdgeZone, её нужно создать. Phaser.Geom предоставляет классы для всех основных форм. В примере создаётся пять разных фигур, центрированных в точке (0, 0), но в итоге используется треугольник (shape5).

Вот как создаётся каждая из них:

const shape1 = new Phaser.Geom.Circle(0, 0, 100);
const shape2 = new Phaser.Geom.Ellipse(0, 0, 500, 150);
const shape3 = new Phaser.Geom.Rectangle(-150, -150, 300, 300);
const shape4 = new Phaser.Geom.Line(-150, -150, 150, 150);
const shape5 = new Phaser.Geom.Triangle(0, -200, 200, 200, -200, 200);

Работа с центром в (0,0) удобна, потому что позиция эмиттера (x: 400, y: 300) станет точкой привязки для всей этой геометрии. Частицы будут испускаться вдоль границы треугольника, но уже смещённого в координаты (400, 300) на сцене.

Анатомия эмиттера: от частот до угасания

Помимо зоны испускания, эмиттер настраивается множеством других параметров, которые управляют поведением частиц. Давайте разберём ключевые из конфига примера.

Полная конфигурация эмиттера:

particles.createEmitter({
    frame: [ 'red', 'yellow', 'green', 'blue' ],
    x: 400, y: 300,
    speed: 90,
    lifespan: 3000,
    quantity: 48,
    frequency: 2000,
    delay: 1000,
    scale: { start: 0.4, end: 0 },
    blendMode: 'ADD',
    emitZone: { type: 'edge', source: shape5, quantity: 48 }
});

* frame: Частицы будут случайным образом брать один из четырёх цветов спрайта из атласа 'flares'. * speed: Частицы получат скорость 90 пикселей в секунду, двигаясь по направлению от точки своего рождения на границе фигуры. * lifespan: Время жизни частицы — 3000 мс (3 секунды). * quantity: За один «выстрел» эмиттер создаст 48 частиц. Это должно совпадать или быть кратно quantity в emitZone для равномерного покрытия фигуры. * frequency: Эмиттер будет активироваться каждые 2000 мс (2 секунды). * delay: Первый выброс частиц произойдёт с задержкой в 1000 мс после создания сцены. * scale: Частица начнёт жизнь с масштаба 0.4 и плавно уменьшится до 0 к концу жизни, создавая эффект растворения. * blendMode: 'ADD': Режим наложения 'ADD' (сложение) делает яркие цвета ещё ярче, что отлично подходит для огней, свечений и энергетических эффектов.

Связка EmitZone и Particle Quantity

Взаимодействие параметров quantity эмиттера и quantity зоны испускания — ключевой момент для понимания. В примере оба значения равны 48.

Это означает, что когда срабатывает эмиттер (по таймеру frequency), он запрашивает создание 48 частиц. Система EdgeZone получает этот запрос и генерирует 48 уникальных точек на границе фигуры-источника (shape5). В результате каждая из 48 частиц рождается в своей собственной, случайной позиции на контуре треугольника, создавая эффект мгновенного и равномерного «зажигания» всего контура.

Если бы quantity эмиттера было меньше (например, 12), то EdgeZone всё равно подготовила бы 48 точек, но эмиттер использовал бы только первые 12 из этого набора. Это полезно для создания менее плотных эффектов или последовательного «пробегания» частиц по контуру.

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

Использование EdgeZone открывает путь к созданию сложных и точных частицевых эффектов, привязанных к геометрии игрового мира. Вы можете анимировать саму фигуру-источник (менять её размер, вращать), и частицы будут следовать за её новым контуром. Для экспериментов попробуйте: заменить shape5 на другие созданные фигуры прямо в коде; анимировать source через this.tweens; использовать blendMode: 'SCREEN' для другого вида свечения; или уменьшить frequency до 100, чтобы создать постоянный поток частиц вдоль фигуры.