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

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

Версия 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.image('bg', 'assets/skies/darkstone.png');
        this.load.image('spark', 'assets/particles/elec3.png');
    }

    create ()
    {
        this.add.image(400, 300, 'bg');

        const emitter = this.add.particles(0, 0, 'spark', {
            scale: 0.5,
            lifespan: 10000,
            gravityY: -50,
            frequency: 20,
            maxVelocityX: 200,
            maxVelocityY: 200,
            blendMode: 'ADD'
        });

        const shape1 = new Phaser.Geom.Rectangle(0, 600, 800, 128);

        emitter.addEmitZone({ type: 'random', source: shape1 });

        emitter.createGravityWell({
            x: 400,
            y: 150,
            power: 4.2,
            epsilon: 250,
            gravity: 100
        });
    }
}

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

const game = new Phaser.Game(config);

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

В методе create сцены мы создаем основной эмиттер частиц (ParticleEmitter), используя метод this.add.particles. Первые два аргумента (0, 0) задают начальные координаты самого эмиттера, но, как мы увидим позже, место испускания частиц определяется отдельно с помощью Emit Zone.

Ключевой момент — конфигурационный объект, передаваемый четвертым аргументом. Он определяет поведение и внешний вид всех частиц.

const emitter = this.add.particles(0, 0, 'spark', {
    scale: 0.5,
    lifespan: 10000,
    gravityY: -50,
    frequency: 20,
    maxVelocityX: 200,
    maxVelocityY: 200,
    blendMode: 'ADD'
});

- scale: 0.5: Устанавливает размер каждой частицы в половину от исходного изображения. - lifespan: 10000: Частица будет жить 10 секунд (значение в миллисекундах), прежде чем исчезнуть. - gravityY: -50: Применяет постоянное ускорение вверх (отрицательное значение по оси Y) ко всем частицам, создавая эффект "всплывания". - frequency: 20: Частицы будут создаваться каждые 20 миллисекунд (50 частиц в секунду). - maxVelocityX и maxVelocityY: Ограничивают максимальную скорость частицы по осям. Это предотвращает неконтролируемое разлетание. - blendMode: 'ADD': Режим наложения 'ADD' (сложение) делает светлые частицы ярче при пересечении, идеально подходит для эффектов огня, электричества или энергии.

Определение зоны испускания (Emit Zone)

По умолчанию частицы рождались бы в точке (0, 0) — координатах эмиттера. Однако мы хотим, чтобы они появлялись в нижней части экрана. Для этого используется Emit Zone — геометрическая область, из которой случайным образом выбираются точки рождения.

Сначала создаем фигуру — прямоугольник (Phaser.Geom.Rectangle). Его параметры: x, y, ширина, высота.

const shape1 = new Phaser.Geom.Rectangle(0, 600, 800, 128);

Эта фигура расположена за нижней границей экрана (y = 600) и имеет ширину во весь экран (800) и высоту 128 пикселя. Таким образом, частицы будут появляться из невидимой горизонтальной полосы под экраном.

Затем мы добавляем эту фигуру в эмиттер как зону испускания с типом 'random'.

emitter.addEmitZone({ type: 'random', source: shape1 });

Параметр type: 'random' указывает, что каждая новая частица должна появляться в случайной точке внутри заданной фигуры (shape1). Это создает равномерное распределение по всей ширине нижней границы.

Добавление гравитационной ямы (Gravity Well)

Самый интересный элемент — гравитационная яма. Она создает силу притяжения к заданной точке, заставляя частицы, которые изначально всплывают вверх, изгибать свою траекторию и стремиться к центру ямы.

Гравитационная яма добавляется методом createGravityWell объекта эмиттера.

emitter.createGravityWell({
    x: 400,
    y: 150,
    power: 4.2,
    epsilon: 250,
    gravity: 100
});

Разберем параметры: - x: 400, y: 150: Координаты центра гравитационной ямы на сцене. В нашем случае — точка в верхней половине экрана. - power: 4.2: Определяет степень (экспоненту) силы притяжения. Значение больше 1 создает нелинейное притяжение, которое резко усиливается при приближении к центру. Это делает эффект более драматичным и "вихревым". - epsilon: 250: Минимальное расстояние, на котором сила притяжения все еще действует. Если частица находится дальше 250 пикселей от центра ямы, сила притяжения не применяется. Это оптимизация и способ контролировать область влияния. - gravity: 100: Основная сила ("гравитационная постоянная") притяжения. Чем выше значение, тем сильнее яма притягивает частицы. В сочетании с gravityY: -50 у эмиттера возникает борьба сил: общее ускорение вверх и локальное притяжение к точке (400, 150).

Как взаимодействуют все силы

Итоговое движение частицы — это суперпозиция (наложение) нескольких сил, которые рассчитываются в каждом кадре: 1. **Начальная скорость:** Частица появляется в случайной точке внизу с нулевой скоростью. 2. **Глобальная гравитация эмиттера (gravityY: -50):** Постоянно придает частице ускорение вверх. 3. **Сила гравитационной ямы:** Начинает действовать, когда частица появляется в зоне видимости и находится в пределах epsilon (250 пикселей) от точки (400, 150). Сила направлена к центру ямы и ее величина зависит от расстояния (power) и общей силы (gravity). 4. **Ограничение скорости (maxVelocityX/Y):** Не позволяет результирующей скорости частицы превысить 200 пикселей в секунду по любой оси, что стабилизирует анимацию.

Визуальный результат: из-под экрана рождаются "искры", которые сначала равномерно всплывают вверх, но по мере приближения к центру экрана начинают закручиваться и втягиваться в точку притяжения, создавая динамичный поток.

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

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

  1. Изменить type в addEmitZone на 'edge' для испускания частиц только по контуру фигуры
  2. Добавить несколько гравитационных ям с разными параметрами (power, gravity), чтобы создать сложное силовое поле
  3. Использовать follow или emitFrom методы эмиттера, чтобы привязать источник частиц или гравитационную яму к движущемуся игровому объекту, создавая шлейф или эффект поглощения