О чем этот пример
При работе с системой частиц в Phaser 3 порядок слоёв влияет на визуальное восприятие сцены. По умолчанию эмиттеры, созданные первыми, оказываются внизу стопки отрисовки, что может привести к нежелательному перекрытию эффектов. В этой статье мы разберём, как динамически менять порядок эмиттеров, используя встроенные методы управления дисплей-листом, и зачем это полезно для создания сложных визуальных композиций.
Версия 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.spritesheet('veg', 'assets/sprites/fruitnveg64wh37.png', { frameWidth: 64, frameHeight: 64 });
}
create ()
{
const particles = this.add.particles('veg');
// The emitters created first are placed at the bottom of the display list, just like sprites and other game objects
const cherries = particles.createEmitter({
frame: 0,
x: 400,
y: 300,
speed: 100,
frequency: 150,
lifespan: 2000
});
const orange = particles.createEmitter({
frame: 1,
x: 400,
y: 300,
speed: 100,
frequency: 150,
lifespan: 2000
});
const turnip = particles.createEmitter({
frame: 2,
x: 400,
y: 300,
speed: 100,
frequency: 150,
lifespan: 2000
});
this.input.once('pointerdown', pointer =>
{
// Move the cherries to the top of the display list
particles.emitters.bringToTop(cherries);
});
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Проблема порядка по умолчанию
В Phaser 3 эмиттеры частиц ведут себя как обычные игровые объекты в контексте дисплей-листа. Это означает, что объект, добавленный на сцену первым, будет отрисован первым и, следовательно, может быть перекрыт объектами, добавленными позже.
При создании нескольких эмиттеров из одного менеджера (ParticleEmitterManager) это правило также применяется. Например, если у вас есть эффекты дыма и искр, и вы хотите, чтобы дым был сверху, нужно управлять их порядком. Без этого искры могут визуально "пересекать" дым, что выглядит неестественно.
В предоставленном примере три эмиттера создаются последовательно: вишни (cherries), апельсин (orange) и репа (turnip). Без вмешательства репа будет поверх апельсина, а апельсин — поверх вишен.
Создание менеджера и эмиттеров
В методе create() сцены сначала создаётся менеджер частиц, который будет управлять всеми эмиттерами. Затем создаются три отдельных эмиттера с разными кадрами (frame) спрайтшита, но с одинаковыми базовыми параметрами: позицией, скоростью, частотой и временем жизни.
Здесь важно, что cherries создан первым, поэтому по умолчанию он будет в самом низу стека отрисовки.
const particles = this.add.particles('veg');
const cherries = particles.createEmitter({
frame: 0,
x: 400,
y: 300,
speed: 100,
frequency: 150,
lifespan: 2000
});
const orange = particles.createEmitter({
frame: 1,
x: 400,
y: 300,
speed: 100,
frequency: 150,
lifespan: 2000
});
const turnip = particles.createEmitter({
frame: 2,
x: 400,
y: 300,
speed: 100,
frequency: 150,
lifespan: 2000
});
Массив `emitters` и метод `bringToTop`
Ключевой момент — доступ к массиву emitters менеджера частиц (particles). Этот массив содержит все созданные для данного менеджера эмиттеры и предоставляет методы для управления их порядком, аналогичные методам для обычных контейнеров в Phaser.
Метод bringToTop() принимает объект эмиттера в качестве аргумента и перемещает его на самый верх дисплей-листа внутри этого менеджера. Это означает, что данный эмиттер будет отрисовываться поверх всех остальных эмиттеров того же менеджера.
// particles — это созданный ранее ParticleEmitterManager
// cherries — это один из созданных эмиттеров
particles.emitters.bringToTop(cherries);
Динамическое изменение порядка
В примере изменение порядка привязано к событию клика мыши (pointerdown). Это демонстрирует, как можно реагировать на действия игрока или другие игровые события для изменения визуальной композиции в реальном времени.
После клика эмиттер cherries, который изначально был внизу, перемещается наверх. Теперь частицы вишен будут отрисовываться поверх частиц апельсина и репы.
this.input.once('pointerdown', pointer => {
particles.emitters.bringToTop(cherries);
});
Такой подход полезен, например, когда эффект должен стать более заметным в определённый момент (вспышка, взрыв) или когда глубина эффекта зависит от положения игрового объекта.
Другие полезные методы управления порядком
Массив emitters предоставляет не только bringToTop. Вот другие методы, которые могут пригодиться для тонкой настройки:
* sendToBack(emitter): Перемещает эмиттер в самый низ списка отрисовки.
* moveUp(emitter): Перемещает эмиттер на одну позицию выше.
* moveDown(emitter): Перемещает эмиттер на одну позицию ниже.
* getIndex(emitter): Возвращает текущий индекс эмиттера в списке.
* setIndex(emitter, index): Устанавливает эмиттер на конкретную позицию по индексу.
Эти методы дают полный контроль над z-order (порядком по глубине) ваших визуальных эффектов, позволяя создавать сложные многослойные композиции из частиц.
Что попробовать дальше
Управление порядком эмиттеров — мощный инструмент для создания профессиональных визуальных эффектов в Phaser 3. Используя методы массива emitters, вы можете гарантировать, что ваши частицы будут взаимодействовать с окружением и друг с другом так, как задумано.
**Идеи для экспериментов:**
1. Свяжите порядок эмиттера с высотой (`y`) игрового персонажа, чтобы эффект пыли из-под ног всегда был под ним.
2. Создайте меню с частицами на заднем плане и динамически меняйте их порядок при наведении на разные кнопки.
3. Используйте moveUp и moveDown по таймеру, чтобы создать эффект "мерцания" или плавного перехода между слоями эффектов.
