О чем этот пример
Создание визуальных эффектов — ключевая часть геймдева, и система частиц Phaser предлагает мощные инструменты для этого. Стандартный эмиттер часто выпускает частицы из одной точки, но что, если нужно заполнить частицами контур сложной фигуры? В этой статье мы разберем пример использования зон испускания (Emit Zones) для генерации частиц из геометрических фигур: кругов, эллипсов, прямоугольников, линий и треугольников. Этот подход позволит вам легко создавать эффекты магических кругов, силовых полей, лазерных лучей и многое другое, напрямую связывая физику частиц с геометрией вашего мира.
Версия 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.image('spark', 'assets/particles/blue.png');
}
create ()
{
const emitter = this.add.particles('spark').createEmitter({
x: 400,
y: 300,
blendMode: 'SCREEN',
scale: { start: 0.2, end: 0 },
speed: { min: -100, max: 100 },
quantity: 50
});
const emitZones = [];
emitZones.push({
source: new Phaser.Geom.Circle(0, 0, 100),
type: 'edge',
quantity: 50
});
emitZones.push({
source: new Phaser.Geom.Ellipse(0, 0, 400, 100),
type: 'edge',
quantity: 50
});
emitZones.push({
source: new Phaser.Geom.Rectangle(-150, -150, 300, 300),
type: 'edge',
quantity: 50
});
emitZones.push({
source: new Phaser.Geom.Line(-150, -150, 150, 150),
type: 'edge',
quantity: 50
});
emitZones.push({
source: new Phaser.Geom.Triangle(0, -200, 200, 200, -200, 200),
type: 'edge',
quantity: 50
});
let emitZoneIndex = 0;
this.input.on('pointermove', pointer =>
{
emitter.setPosition(pointer.x, pointer.y);
});
this.input.on('pointerdown', pointer =>
{
emitZoneIndex = (emitZoneIndex + 1) % emitZones.length;
emitter.setEmitZone(emitZones[emitZoneIndex]);
emitter.explode();
});
emitter.setEmitZone(emitZones[emitZoneIndex]);
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Настройка базового эмиттера частиц
Всё начинается с создания обычного эмиттера частиц. В методе create() сцены мы инициализируем эмиттер, используя заранее загруженную текстуру частицы.
const emitter = this.add.particles('spark').createEmitter({
x: 400,
y: 300,
blendMode: 'SCREEN',
scale: { start: 0.2, end: 0 },
speed: { min: -100, max: 100 },
quantity: 50
});
Ключевые параметры здесь:
* `blendMode: 'SCREEN'` — задаёт режим наложения, при котором светлые частицы "осветляют" фон, создавая эффект свечения.
* `scale: { start: 0.2, end: 0 }` — каждая частица плавно уменьшается от 20% размера до полного исчезновения.
* `speed: { min: -100, max: 100 }` — частицам задаётся случайный вектор скорости в диапазоне от -100 до 100 пикселей в секунду по обеим осям, создавая хаотичное движение.
* `quantity: 50` — количество частиц, испускаемых за один вызов. Эмиттер пока не активирован, частицы будут появляться только по команде.
Создание библиотеки геометрических зон испускания
Сердце примера — массив emitZones. Каждый его элемент является конфигурационным объектом для зоны испускания. Зона определяет, *откуда* и *как* появляются новые частицы.
const emitZones = [];
emitZones.push({
source: new Phaser.Geom.Circle(0, 0, 100),
type: 'edge',
quantity: 50
});
// ... аналогично добавляются Ellipse, Rectangle, Line, Triangle
Свойства зоны:
* source — экземпляр геометрической фигуры из модуля Phaser.Geom. Координаты фигуры задаются относительно позиции эмиттера.
* type: 'edge' — указывает, что частицы должны появляться строго на границе (контуре) фигуры. Альтернатива — 'random', для случайного распределения внутри фигуры.
* quantity — переопределяет глобальную настройку эмиттера для этой зоны. Здесь 50 частиц будут равномерно распределены по контуру выбранной фигуры.
Управление эмиттером и переключение фигур
Пример добавляет два типа интерактивности: перемещение источника эффекта и смену фигуры, из которой испускаются частицы.
this.input.on('pointermove', pointer => {
emitter.setPosition(pointer.x, pointer.y);
});
При движении мыши позиция всего эмиттера (и, как следствие, всех его зон испускания) обновляется методом setPosition(). Это заставляет облако частиц следовать за курсором.
let emitZoneIndex = 0;
this.input.on('pointerdown', pointer => {
emitZoneIndex = (emitZoneIndex + 1) % emitZones.length;
emitter.setEmitZone(emitZones[emitZoneIndex]);
emitter.explode();
});
По клику мыши происходит три действия:
1. Индекс текущей зоны циклически переключается на следующую в массиве.
2. Метод emitter.setEmitZone() применяет новую, выбранную по индексу, конфигурацию зоны к эмиттеру.
3. Метод emitter.explode() мгновенно испускает ровно то количество частиц, которое указано в активной зоне (50), размещая их по её контуру. Это создаёт мгновенную вспышку частиц в форме фигуры.
Практические советы и применение
Этот паттерн открывает множество возможностей для игровых эффектов.
// Пример: создание статичного энергетического щита в форме шестиугольника
const hexagon = new Phaser.Geom.Polygon([
new Phaser.Geom.Point(0, -80),
new Phaser.Geom.Point(69, -40),
new Phaser.Geom.Point(69, 40),
new Phaser.Geom.Point(0, 80),
new Phaser.Geom.Point(-69, 40),
new Phaser.Geom.Point(-69, -40)
]);
const shieldEmitter = this.add.particles('energy').createEmitter({
lifespan: 1000,
scale: { start: 0.5, end: 0 },
blendMode: 'ADD',
emitZone: { source: hexagon, type: 'edge', quantity: 20 },
frequency: 100 // Испускает 20 частиц каждые 100 мс по контуру
});
shieldEmitter.start();
Идеи для использования:
* **Линия (Line)**: идеальна для эффектов лазерного луча или молнии.
* **Эллипс (Ellipse)**: можно создать эффект орбиты или энергетического кольца вокруг объекта.
* **Прямоугольник (Rectangle) с типом 'random'**: заполнение дымом или искрами внутри заданной области (например, разрушаемого блока).
Главное — помнить, что координаты фигуры-источника (source) задаются относительно позиции эмиттера, что позволяет легко привязывать сложные эффекты к движущимся игровым объектам.
Что попробовать дальше
Использование EmitZone с геометрическими фигурами — это мощный приём для выхода за рамки точечных эффектов. Вы можете проектировать визуалы, напрямую соответствующие форме игровых объектов или зон. Для экспериментов попробуйте: комбинировать несколько эмиттеров с разными фигурами в одном эффекте; анимировать саму фигуру-источник (например, вращая или масштабируя её) и обновлять зону эмиттера в update(); использовать тип 'random' для заполнения частицами площади сложного полигона, создавая эффекты тумана или скопления звёзд.
