О чем этот пример
Визуальные эффекты на основе частиц — ключевой элемент атмосферы в играх. Phaser 3 предоставляет мощную систему Particle Emitter, но настоящая магия начинается, когда вы управляете местом появления частиц. В этой статье мы разберем, как использовать геометрические фигуры в качестве источника для эмиттеров, создавая сложные и контролируемые эффекты, такие как кольца, волны или пульсирующие сферы. Вы научитесь определять, будут ли частицы рождаться внутри фигуры или строго на её границе, и как это влияет на визуальный результат.
Версия 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, 180);
const shape2 = new Phaser.Geom.Circle(0, 0, 200);
const particles = this.add.particles('flares');
particles.createEmitter({
frame: 'red',
x: 400, y: 300,
lifespan: 2000,
quantity: 4,
scale: 0.2,
alpha: { start: 1, end: 0 },
blendMode: 'ADD',
emitZone: { type: 'random', source: shape1 }
});
particles.createEmitter({
frame: 'yellow',
x: 400, y: 300,
speed: 0,
lifespan: 1000,
quantity: 1,
scale: { start: 0.4, end: 0 },
blendMode: 'ADD',
emitZone: { type: 'edge', source: shape2, quantity: 48, yoyo: false }
});
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Загрузка атласа частиц
Работа с частицами в Phaser часто начинается с загрузки атласа — изображения, содержащего набор спрайтов (фреймов) для частиц. Это эффективнее, чем загружать множество отдельных файлов.
В методе preload мы используем this.load.atlas(). Первый аргумент — ключ ресурса ('flares'), по которому мы будем к нему обращаться. Второй и третий — пути к изображению и JSON-файлу с данными о расположении фреймов.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('flares', 'assets/particles/flares.png', 'assets/particles/flares.json');
Создание фабрики частиц и эмиттеров
Эмиттер нельзя создать просто в сцене. Сначала нужно создать фабрику (менеджер) частиц с помощью this.add.particles(), передав ключ загруженного атласа. Эта фабрика будет управлять всеми эмиттерами, которые мы к ней добавим.
Затем мы вызываем метод .createEmitter() у фабрики, передавая конфигурационный объект. В этом объекте определяются все свойства частиц: фрейм для текстуры, начальные координаты (`x,y), время жизни (lifespan), количество частиц, выпускаемых за один цикл (quantity`), и многое другое.
const particles = this.add.particles('flares');
particles.createEmitter({
frame: 'red',
x: 400, y: 300,
lifespan: 2000,
quantity: 4,
scale: 0.2,
alpha: { start: 1, end: 0 },
blendMode: 'ADD',
emitZone: { type: 'random', source: shape1 }
});
Зона эмиттера типа 'random'
Ключевой параметр в нашем примере — emitZone. Он определяет область, в которой будут появляться новые частицы. При type: 'random' частицы будут рождаться в случайной точке **внутри** заданной геометрической фигуры (source).
Мы создаем объект Phaser.Geom.Circle — круг с центром в точке (0, 0) и радиусом 180 пикселей. Обратите внимание: координаты эмиттера заданы отдельно (x: 400, y: 300), а центр круга находится в (0,0) относительно этой точки. Поэтому частицы будут появляться в случайном месте внутри круга радиусом 180 пикселей вокруг центра (400, 300).
const shape1 = new Phaser.Geom.Circle(0, 0, 180);
// ... внутри createEmitter:
emitZone: { type: 'random', source: shape1 }
Зона эмиттера типа 'edge'
Второй тип зоны — 'edge'. В отличие от 'random', частицы будут появляться строго **на границе** фигуры. Это идеально для создания контурных эффектов, например, силового поля или кольца.
Мы создаем второй круг с радиусом 200. В конфигурации зоны появляются новые параметры: quantity определяет, сколько точек на границе фигуры будет использоваться для расчета позиций (чем больше, тем равномернее распределение). Параметр yoyo в данном контексте не применяется для зон типа 'edge' и может быть опущен.
const shape2 = new Phaser.Geom.Circle(0, 0, 200);
// ... внутри createEmitter:
emitZone: { type: 'edge', source: shape2, quantity: 48, yoyo: false }
Настройка поведения частиц
Помимо зоны эмиттера, конфигурация позволяет тонко настраивать поведение и внешний вид каждой частицы. Сравним два эмиттера из примера:
* **Красные частицы (`frame: 'red'`)**: Появляются внутри круга (`random`), живут 2 секунды (`lifespan: 2000`), затухают от непрозрачных к прозрачным (`alpha: { start: 1, end: 0 }`).
* **Желтые частицы (`frame: 'yellow'`)**: Появляются на границе круга (`edge`), не имеют начальной скорости (`speed: 0`), живут 1 секунду и масштабируются от размера 0.4 до 0 (`scale: { start: 0.4, end: 0 }`), создавая эффект "схлопывания".
// Свойства для эффекта схлопывания
speed: 0,
lifespan: 1000,
scale: { start: 0.4, end: 0 },
Что попробовать дальше
Использование emitZone с геометрическими фигурами открывает огромный простор для создания сложных визуальных эффектов без необходимости вручную рассчитывать координаты. Вы можете экспериментировать: замените Phaser.Geom.Circle на Phaser.Geom.Rectangle, Phaser.Geom.Line или Phaser.Geom.Triangle. Попробуйте анимировать саму фигуру-источник (меняя её радиус или координаты) во время работы эмиттера — это создаст динамические эффекты расходящихся волн или пульсирующих облаков. Комбинируя несколько эмиттеров с разными зонами и настройками, вы сможете собрать практически любой необходимый эффект.
