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

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

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

    create ()
    {
        const emitter = this.add.particles(100, 100, 'bubbles', {
            frame: [ 'bluebubble', 'redbubble', 'greenbubble', 'silverbubble' ],
            lifespan: 5000,
            angle: { min: -30, max: 30 },
            speed: 150,
            frequency: 200
        });

        // this.add.particles2('bubbles', {
        //     frame: 'bluebubble',
        //     x: 300,
        //     y: 100,
        //     lifespan: 5000,
        //     angle: { min: -30, max: 30 },
        //     speed: 150,
        //     frequency: 200
        // });

        this.add.particles(300, 400, 'bubbles', {
            frame: { frames: [ 'bluebubble', 'redbubble' ], cycle: true, quantity: 4 },
            lifespan: 5000,
            angle: { min: -30, max: 30 },
            speed: 150,
            frequency: 200
        });

        window.emma = emitter;
    }
}

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

const game = new Phaser.Game(config);

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

Перед созданием эмиттера необходимо загрузить ресурсы. В данном примере используется атлас — один PNG-файл, содержащий несколько спрайтов (кадров), и JSON-файл с их координатами. Это эффективно для производительности.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('bubbles', 'assets/particles/bubbles.png', 'assets/particles/bubbles.json');

Метод this.load.atlas() загружает атлас под ключом 'bubbles'. Теперь мы можем обращаться к отдельным кадрам, таким как 'bluebubble' или 'redbubble'.

Простой список кадров

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

const emitter = this.add.particles(100, 100, 'bubbles', {
    frame: [ 'bluebubble', 'redbubble', 'greenbubble', 'silverbubble' ],
    lifespan: 5000,
    angle: { min: -30, max: 30 },
    speed: 150,
    frequency: 200
});

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

Управляемая последовательность кадров

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

this.add.particles(300, 400, 'bubbles', {
    frame: { frames: [ 'bluebubble', 'redbubble' ], cycle: true, quantity: 4 },
    lifespan: 5000,
    angle: { min: -30, max: 30 },
    speed: 150,
    frequency: 200
});

Здесь frame — это объект со свойствами: - frames: Массив кадров для последовательности. - cycle: Булево значение. Если true, эмиттер будет циклически перебирать кадры в массиве для каждой новой частицы (синяя, красная, синяя, красная...). - quantity: Количество частиц, которые будут испущены для текущего кадра перед переходом к следующему. В данном случае 4 синих пузырька, затем 4 красных, и так по циклу.

Практические отличия подходов

Выбор между массивом и объектом с последовательностью зависит от задачи.

* **Массив (frame: [ ... ])**: Идеален для создания хаотичного, разноцветного эффекта, где каждая частица независима (например, искры от костра, разноцветные конфетти). * **Объект с последовательностью (frame: { frames: [...], cycle: true, quantity: N })**: Позволяет создавать волны, пульсации или эффекты с чёткой сменой фаз. Например, имитация взрыва, где сначала идёт жёлтое ядро (quantity: 10), затем оранжевые языки пламени (quantity: 20), и наконец, серая дымка (quantity: 30).

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

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

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

  1. Создать эмиттер дыма, где частицы постепенно меняют кадр от тёмного к светлому, имитируя рассеивание
  2. Сделать «волшебный» след за персонажем, где кадры циклически меняются, создавая эффект переливания
  3. Комбинировать несколько эмиттеров с разными стратегиями выбора кадров для сложных эффектов вроде метеоритного дождя