О чем этот пример

Порядок отрисовки спрайтов и частиц в 2D-играх критически важен для визуальной целостности сцены. Частицы от взрыва должны быть поверх снаряда, но под интерфейсом. Встроенная в Phaser система глубины (depth) решает эту задачу глобально, но что, если нужно быстро изменить порядок отрисовки только для частиц конкретного эмиттера? На помощь приходит свойство `particleBringToTop`. Эта статья на практическом примере покажет, как динамически менять слой отрисовки частиц относительно других игровых объектов.

Версия 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.atlas('blocks', 'assets/sprites/blocks.png', 'assets/sprites/blocks.json');
    }

    create ()
    {
        const emitter = this.add.particles(100, 300);

        emitter.setConfig({
            texture: 'blocks',
            frame: 'redmonster',
            lifespan: 5000,
            angle: { min: -30, max: 30 },
            speed: 150,
            frequency: 200
        });

        const text = this.add.text(10, 10, 'Click to change. bringToTop: true');

        this.input.on('pointerdown', () => {

            if (emitter.particleBringToTop)
            {
                emitter.particleBringToTop = false;
            }
            else
            {
                emitter.particleBringToTop = true;
            }

            text.setText(`Click to change. bringToTop: ${emitter.particleBringToTop}`);

        });

        window.emma = emitter;
    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#000',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Создание эмиттера частиц с текстурой из атласа

В методе preload загружается атлас текстур blocks, который содержит несколько спрайтов в одном изображении. Это эффективный способ работы с графикой.

this.load.atlas('blocks', 'assets/sprites/blocks.png', 'assets/sprites/blocks.json');

В create создается эмиттер частиц в точке (100, 300). Конфигурация задается методом setConfig. Ключевые параметры: * texture и frame: определяют, какое изображение из атласа будет использоваться для каждой частицы (в данном случае кадр с именем 'redmonster'). * lifespan: время жизни частицы в миллисекундах. * angle и speed: определяют направление и скорость разлета. * frequency: интервал между испусканием частиц.

const emitter = this.add.particles(100, 300);
emitter.setConfig({
    texture: 'blocks',
    frame: 'redmonster',
    lifespan: 5000,
    angle: { min: -30, max: 30 },
    speed: 150,
    frequency: 200
});

Свойство particleBringToTop и его роль

Эмиттер частиц в Phaser — это контейнер (ParticleEmitter), который управляет множеством отдельных частиц, являющихся игровыми объектами (Particle). По умолчанию частицы отрисовываются в том порядке, в котором они были добавлены в сцену относительно других объектов.

Свойство particleBringToTop — это флаг, принадлежащий самому эмиттеру. Когда он установлен в true, **все частицы, испускаемые этим эмиттером, будут принудительно отрисовываться поверх всех других игровых объектов в этой сцене**. Это локальная и быстрая альтернатива ручной настройке свойства depth для каждого эмиттера или объектов вокруг него.

Важно: это свойство влияет на все частицы эмиттера, включая уже выпущенные. Его переключение немедленно изменит порядок отрисовки.

Динамическое переключение порядка отрисовки

В примере добавлен текст для отображения текущего состояния и обработчик клика мыши. По каждому клику значение particleBringToTop инвертируется, что мгновенно меняет слой, на котором рисуются частицы.

const text = this.add.text(10, 10, 'Click to change. bringToTop: true');

this.input.on('pointerdown', () => {
    if (emitter.particleBringToTop)
    {
        emitter.particleBringToTop = false;
    }
    else
    {
        emitter.particleBringToTop = true;
    }
    text.setText(`Click to change. bringToTop: ${emitter.particleBringToTop}`);
});

Попробуйте запустить пример и добавить другие спрайты на сцену (например, через this.add.image). Вы увидите, как клик заставляет частицы перескакивать то под, то над этими спрайтами.

Когда использовать bringToTop, а когда систему depth

particleBringToTop — это инструмент для быстрого прототипирования и решения простых задач. * **Используйте его**, когда нужно гарантировать, что частицы эффекта (огонь, дым, магическая аура) всегда будут поверх определенного персонажа или объекта без сложной логики. * **Не используйте его**, если в сцене есть сложная многослойная графика (задний план, средний план, несколько слоев интерфейса). В этом случае надежнее использовать встроенную систему глубины Phaser, назначая объектам и эмиттерам числовые значения depth. Объекты с большим значением depth отрисовываются поверх объектов с меньшим значением.

// Альтернатива: явное управление глубиной
emitter.setDepth(10);
someBackgroundImage.setDepth(1);
playerSprite.setDepth(5);

particleBringToTop по сути временно присваивает частицам очень большое значение глубины.

Что попробовать дальше

Свойство particleBringToTop — это удобный переключатель для управления визуальным приоритетом частиц в реальном времени. Оно идеально подходит для отладки, прототипирования визуальных эффектов и реализации механик, где порядок отрисовки должен меняться по игровым событиям (например, частицы щита поверх врага). **Идеи для экспериментов:** 1. Создайте два эмиттера с разными текстурами и переключайте bringToTop только у одного. Наблюдайте за их взаимодействием. 2. Добавьте анимацию спрайту и попробуйте «спрятать» его за частицами дыма, отключив флаг. 3. Свяжите переключение флага не с кликом, а с игровым событием, например, с получением урона игроком (частицы крови поверх всего).