О чем этот пример
Эффекты частиц — один из самых простых способов добавить игре визуальную глубину и динамику. В этом примере мы не просто разбрасываем частицы хаотично, а используем геометрические фигуры Phaser для создания сложных, управляемых визуальных образов. Вы научитесь управлять зонами испускания (`emitZone`), настраивать жизненный цикл частиц и создавать несколько эмиттеров для одного партикл-менеджера, чтобы собрать из простых элементов цельную картину — новогоднюю ёлку.
Версия 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 tree = new Phaser.Geom.Triangle.BuildEquilateral(0, -250, 400);
const trunk = new Phaser.Geom.Rectangle(0, 0, 80, 140);
const baubles = new Phaser.Geom.Line(0, 0, 170, 60);
const baubles2 = new Phaser.Geom.Line(0, 0, 310, 70);
const particles = this.add.particles('flares');
particles.createEmitter({
frame: 'green',
x: 400, y: 300,
speed: 0,
lifespan: 2000,
delay: 500,
quantity: 48,
frequency: 2000,
scale: { start: 0.4, end: 0.1 },
blendMode: 'ADD',
emitZone: { type: 'edge', source: tree, quantity: 48 }
});
particles.createEmitter({
frame: 'blue',
x: 360, y: 420,
speed: 0,
lifespan: 500,
delay: 500,
frequency: 0,
quantity: 1,
scale: 0.2,
blendMode: 'ADD',
emitZone: { type: 'edge', source: trunk, quantity: 48 }
});
particles.createEmitter({
frame: 'red',
x: 400, y: 300,
lifespan: 500,
quantity: 1,
frequency: 200,
scale: 0.6,
blendMode: 'ADD',
emitZone: { type: 'edge', source: tree, quantity: 12 }
});
particles.createEmitter({
frame: { frames: [ 'red', 'yellow', 'blue' ], cycle: true },
x: 340, y: 200,
lifespan: 200,
quantity: 1,
frequency: 50,
scale: 0.4,
blendMode: 'ADD',
emitZone: { type: 'edge', source: baubles, quantity: 10 }
});
particles.createEmitter({
frame: { frames: [ 'red', 'yellow', 'blue' ], cycle: true },
x: 280, y: 300,
lifespan: 200,
quantity: 1,
frequency: 50,
scale: 0.4,
blendMode: 'ADD',
emitZone: { type: 'edge', source: baubles2, quantity: 16 }
});
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка атласа
Всё начинается в методе preload. Здесь мы загружаем единственный необходимый ресурс — атлас частиц flares. Атлас содержит несколько текстур (фреймов) для частиц разных цветов в одном изображении.
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.atlas('flares', 'assets/particles/flares.png', 'assets/particles/flares.json');
Метод setBaseURL задаёт базовый путь для загрузчиков, что позволяет указывать только относительные пути к файлам атласа: изображению (flares.png) и JSON-файлу с данными о фреймах (flares.json).
Геометрия как основа визуализации
В методе create мы определяем форму нашей будущей ёлки с помощью встроенных геометрических объектов Phaser. Это ключевой момент: мы не рисуем частицы вручную, а задаём для них области появления.
const tree = new Phaser.Geom.Triangle.BuildEquilateral(0, -250, 400);
const trunk = new Phaser.Geom.Rectangle(0, 0, 80, 140);
const baubles = new Phaser.Geom.Line(0, 0, 170, 60);
const baubles2 = new Phaser.Geom.Line(0, 0, 310, 70);
* tree: Равносторонний треугольник, который станет кроной ёлки. Он строится от точки (0, -250) с длиной стороны 400 пикселей.
* trunk: Прямоугольник для ствола.
* baubles и baubles2: Отрезки, вдоль которых будут появляться гирлянды-шарики.
Все фигуры создаются с началом в точке (0, 0), их позиция будет задана позже через свойства эмиттера `xиy`.
Создание менеджера частиц и эмиттеров
Сначала создаётся менеджер частиц (ParticleEmitterManager), который будет управлять всеми эмиттерами и их визуализацией.
const particles = this.add.particles('flares');
Затем для этого менеджера создаётся несколько эмиттеров методом createEmitter. Каждый эмиттер отвечает за свой визуальный элемент: крону, ствол, вспышки на кроне и две гирлянды. Рассмотрим первый, самый сложный эмиттер для кроны.
particles.createEmitter({
frame: 'green',
x: 400, y: 300,
speed: 0,
lifespan: 2000,
delay: 500,
quantity: 48,
frequency: 2000,
scale: { start: 0.4, end: 0.1 },
blendMode: 'ADD',
emitZone: { type: 'edge', source: tree, quantity: 48 }
});
* frame: Указывает, какой фрейм из атласа ('green') использовать для частиц.
* x, y: Центральная точка, к которой будет привязана зона эмиссии (emitZone).
* speed: 0: Частицы не движутся, они остаются на месте появления.
* lifespan: Время жизни частицы в миллисекундах (2000 мс = 2 секунды).
* delay и frequency: Эмиттер ждёт 500 мс, а затем испускает частицы каждые 2000 мс.
* quantity: Количество частиц, испускаемых за один цикл (48 штук).
* scale: Частицы плавно уменьшаются с 0.4 до 0.1 за время своей жизни.
* blendMode: 'ADD': Режим наложения «сложение» делает яркие частицы ещё ярче при наложении, создавая эффект свечения.
* emitZone: Самая важная настройка. type: 'edge' означает, что частицы будут появляться вдоль рёбер (контура) геометрической фигуры source: tree. Параметр quantity здесь определяет, сколько точек равномерно распределить по контуру фигуры для появления частиц. Для треугольника это 48 точек.
Эмиттеры для деталей: ствол, вспышки и гирлянды
Остальные эмиттеры работают по тому же принципу, но с другими параметрами, создавая разные эффекты.
Эмиттер ствола использует прямоугольник (trunk) в качестве emitZone и испускает 48 синих статичных частиц один раз (частота frequency: 0).
particles.createEmitter({
frame: 'blue',
x: 360, y: 420,
speed: 0,
// ... другие параметры ...
emitZone: { type: 'edge', source: trunk, quantity: 48 }
});
Эмиттер красных вспышек на кроне (tree) испускает по одной крупной частице каждые 200 мс с коротким временем жизни (500 мс), создавая эффект мерцания.
Эмиттеры гирлянд (baubles, baubles2) демонстрируют продвинутую работу с кадрами. Вместо строки они принимают объект конфигурации, который циклически перебирает массив цветов.
frame: { frames: [ 'red', 'yellow', 'blue' ], cycle: true }
Это заставляет каждую новую частицу в гирлянде быть следующего цвета из списка, создавая разноцветную последовательность. Зоной эмиссии для них выступают линии.
Настройка игры и запуск
Финальный шаг — конфигурация и инстанцирование объекта игры Phaser.Game. Мы используем WEBGL-рендерер для корректной работы режима наложения ADD.
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Конфиг передаётся в конструктор Phaser.Game, который запускает игровой цикл и инициализирует нашу сцену Example.
Что попробовать дальше
Этот пример наглядно показывает, как, комбинируя простые геометрические фигуры и настраивая параметры эмиттеров, можно создавать сложные и управляемые визуальные эффекты без использования готовых изображений. Для экспериментов попробуйте: изменить type в emitZone на 'random', чтобы частицы появлялись не по контуру, а случайно внутри фигуры; анимировать свойства `xиyсамого эмиттера, чтобы заставить гирлянды двигаться; или использовать более сложную пользовательскую кривую дляscaleиalpha`, чтобы получить нелинейное затухание частиц.
