О чем этот пример
Визуальные эффекты, такие как фонтаны частиц, часто требуют высокой производительности, особенно при большом количестве объектов. Phaser 3 предоставляет `SpriteGPULayer` — мощный инструмент для рендеринга тысяч спрайтов с использованием аппаратного ускорения GPU. Эта статья покажет, как создать эффектный фонтан из тысяч частиц, эффективно управляя их движением, прозрачностью и вращением, без потери кадров. Вы научитесь настраивать параметры частиц и организовывать их массовую анимацию.
Версия 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('sparkle1', 'assets/particles/sparkle1.png');
}
create ()
{
const pop = 1024 * 8;
const layer = this.add.spriteGPULayer('sparkle1', pop);
console.log(layer);
layer.setBlendMode(Phaser.BlendModes.ADD);
const template = {
x: {
base: 400,
ease: 'Linear',
yoyo: false
},
y: {
base: 500,
ease: 'Gravity',
yoyo: false
},
alpha: {
base: 1,
amplitude: -1,
ease: 'Quad.easeInOut',
yoyo: false
},
rotation: {
ease: 'Linear',
yoyo: false
},
tintTopLeft: 0x5080ff,
tintTopRight: 0x5080ff,
tintBottomLeft: 0x5080ff,
tintBottomRight: 0x5080ff
};
const drift = 1000000 / pop;
const bursts = 16;
for (let j = 0; j < bursts; j++)
{
let a = -Math.random() * Math.PI;
let b = Math.random() * Math.PI;
let delayBase = Math.random() * 1000;
for (let i = 0; i < pop / bursts; i++)
{
const duration = Math.random() * 1000 + 1000;
const delay = i * 1000 / (pop / bursts) + delayBase;
a += (Math.random() * 2 - 1) / drift;
b += (Math.random() * 2 - 1) / drift;
let x = Math.cos(a) * Math.cos(b);
let y = Math.sin(a);
template.x.amplitude = x * 500 - Math.random() * 100;
template.x.duration = duration;
template.x.delay = delay;
template.y.velocity = y * 800 - Math.random() * 100;
template.y.duration = duration;
template.y.delay = delay;
template.alpha.duration = duration;
template.alpha.delay = delay;
template.rotation.base = Math.random() * Math.PI * 2;
template.rotation.amplitude = Math.random() * 6 - 3;
template.rotation.duration = duration;
template.rotation.delay = delay;
template.scaleX = 0.1 * Math.random() + 0.02;
template.scaleY = template.scaleX;
layer.addMember(template);
}
}
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Инициализация SpriteGPULayer
Ключевой объект для работы с массой частиц — SpriteGPULayer. Он создаётся как слой, который может содержать множество спрайтов, использующих одну текстуру, и оптимизирован для рендеринга на GPU.
Сначала загружаем текстуру частицы в preload. Затем в create вычисляем общее количество частиц (pop) и создаём сам слой. Метод setBlendMode устанавливает режим наложения ADD, который идеально подходит для светящихся частиц — цвета складываются, создавая эффект свечения.
const pop = 1024 * 8;
const layer = this.add.spriteGPULayer('sparkle1', pop);
layer.setBlendMode(Phaser.BlendModes.ADD);
Шаблон для настройки частиц
Каждая частица в слое настраивается через объект-шаблон (template). В нём определяются свойства анимации: положение (`x,y), прозрачность (alpha), вращение (rotation), цвет (tint) и масштаб (scaleX,scaleY`).
Свойства используют паттерн с base (базовое значение), amplitude (амплитуда изменения), ease (функция плавности), duration (длительность) и delay (задержка старта). Например, для оси Y используется ease 'Gravity', что имитирует движение под действием гравитации.
const template = {
x: { base: 400, ease: 'Linear', yoyo: false },
y: { base: 500, ease: 'Gravity', yoyo: false },
alpha: { base: 1, amplitude: -1, ease: 'Quad.easeInOut', yoyo: false },
rotation: { ease: 'Linear', yoyo: false },
tintTopLeft: 0x5080ff,
tintTopRight: 0x5080ff,
tintBottomLeft: 0x5080ff,
tintBottomRight: 0x5080ff
};
Генерация и распределение частиц
Чтобы создать эффект фонтана, частицы распределяются порциями (bursts). Для каждой порции вычисляются начальные углы `aиb, которые задают направление разлёта в сферических координатах. ЗадержкаdelayBase` добавляет случайность во времени появления.
Внутри цикла для каждой частицы задаются длительность анимации и индивидуальная задержка. Углы слегка изменяются на каждом шаге (через drift), что создаёт естественное расхождение траекторий. Затем вычисляются компоненты скорости `xиy, которые присваиваются какamplitudeдля оси X иvelocity` для оси Y в шаблоне.
template.x.amplitude = x * 500 - Math.random() * 100;
template.x.duration = duration;
template.x.delay = delay;
template.y.velocity = y * 800 - Math.random() * 100;
template.y.duration = duration;
template.y.delay = delay;
Настройка визуальных параметров
Помимо движения, важно анимировать визуальные свойства. Прозрачность (alpha) уменьшается от 1 до 0 за время duration, создавая эффект исчезновения. Вращение (rotation) задаётся случайным начальным углом (base) и амплитудой, которая определяет скорость вращения.
Масштаб (scaleX, scaleY) устанавливается небольшим и случайным, чтобы частицы выглядели как мелкие искры. Все эти параметры копируются из шаблона для каждой частицы при добавлении её в слой через layer.addMember(template).
template.alpha.duration = duration;
template.alpha.delay = delay;
template.rotation.base = Math.random() * Math.PI * 2;
template.rotation.amplitude = Math.random() * 6 - 3;
template.rotation.duration = duration;
template.rotation.delay = delay;
template.scaleX = 0.1 * Math.random() + 0.02;
template.scaleY = template.scaleX;
layer.addMember(template);
Запуск анимации и настройка сцены
После добавления всех частиц в слой анимация запускается автоматически, согласно заданным задержкам и длительностям. Конфигурация игры (config) должна использовать type: Phaser.WEBGL, так как SpriteGPULayer работает только с WebGL рендерером.
Важно указать корректный parent (контейнер в HTML) и размеры холста. Экземпляр игры создаётся с этой конфигурацией и переданным классом сцены.
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Что попробовать дальше
SpriteGPULayer позволяет создавать сложные частичные системы с тысячами объектов, сохраняя высокую производительность за счёт GPU. Вы можете экспериментировать: измените ease-функции для движения (например, на 'Sine.easeOut'), добавьте изменение цвета частиц со временем через tint, или создайте несколько слоёв с разными текстурами для составных эффектов (огонь и дым). Попробуйте варьировать параметры drift и bursts для контроля над формой фонтана.
