О чем этот пример
В 2D-играх спрайты часто перекрывают друг друга. Когда динамический объект должен оказаться поверх всех остальных, простого изменения координат Y недостаточно — нужно явно управлять порядком отрисовки. В этой статье мы разберем, как работает система глубины (depth) в Phaser и как использовать метод `bringToTop()` для контроля визуальной иерархии объектов. Этот подход полезен для создания карточных игр, инвентарей, интерфейсов и любых сцен, где объекты перемещаются между слоями.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
constructor ()
{
super();
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('block', 'assets/sprites/block.png');
}
create ()
{
// Create a stack of blocks
const group = this.make.group({ key: 'block', frameQuantity: 12 });
Phaser.Actions.SetXY(group.getChildren(), 48, 500, 64, 0);
this.input.on('pointerdown', function (pointer) {
const child = this.children.getAt(0);
child.y -= 32;
this.children.bringToTop(child);
}, this);
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Проблема: статичный порядок отрисовки
По умолчанию Phaser отрисовывает объекты в том порядке, в котором они были добавлены в сцену. Это называется порядком отображения (display list). Если объекты статичны, этого достаточно. Но если объект должен "всплыть" наверх (например, при клике), простое изменение его координаты Y не изменит его позицию в списке отрисовки.
В примере создается вертикальная стопка из 12 блоков. Они добавлены в группу и позиционированы с помощью Phaser.Actions.SetXY. Изначально блоки отрисовываются в порядке добавления: первый блок — внизу, последний — наверху.
Решение: метод `children.bringToTop()`
Ключевой метод для управления порядком — bringToTop(child). Он перемещает указанный дочерний объект в конец списка отрисовки группы, гарантируя, что он будет нарисован поверх всех остальных.
В примере обработчик клика (pointerdown) делает две вещи:
1. Смещает самый нижний блок вверх на 32 пикселя по оси Y.
2. Вызывает bringToTop() для этого блока, чтобы он отобразился поверх остальных.
this.input.on('pointerdown', function (pointer) {
const child = this.children.getAt(0);
child.y -= 32;
this.children.bringToTop(child);
}, this);
Обратите внимание: метод вызывается у this.children, так как в контексте обработчика this ссылается на саму группу (group).
Работа с группами и списком детей
Группа (Group) в Phaser — это контейнер для управления коллекцией игровых объектов. В примере группа создается через this.make.group(). Метод group.getChildren() возвращает массив всех дочерних объектов группы.
const group = this.make.group({ key: 'block', frameQuantity: 12 });
Phaser.Actions.SetXY(group.getChildren(), 48, 500, 64, 0);
Phaser.Actions.SetXY — это хелпер для позиционирования массива объектов. Параметры: начальный X (48), начальный Y (500), шаг по X (64), шаг по Y (0). Так создается вертикальная колонка блоков.
Доступ к конкретному ребенку осуществляется через this.children.getAt(index). Индекс 0 соответствует первому добавленному блоку — самому нижнему в начальной стопке.
Важные нюансы и альтернативы
Метод bringToTop() работает в контексте конкретной группы или списка детей сцены. Если у вас несколько независимых групп, перемещение объекта в одной группе не повлияет на порядок отрисовки между группами. Для управления порядком между разными контейнерами используйте свойство depth.
Более современный и гибкий подход — явное задание глубины через setDepth(value). Объекты с большим значением depth отрисовываются поверх объектов с меньшим значением. Это особенно полезно для сложных сцен с несколькими слоями.
// Альтернатива: использование свойства depth
child.setDepth(100);
Также помните, что bringToTop() изменяет внутренний массив children, что может повлиять на последующие обращения по индексу.
Что попробовать дальше
Метод bringToTop() — это простой и эффективный способ динамического управления видимым порядком объектов в пределах одной группы или списка отрисовки. Он идеально подходит для быстрых прототипов и ситуаций, где нужен эффект "поднятия" объекта наверх по клику или столкновению.
**Идеи для экспериментов:**
1. Измените логику: поднимайте наверх не первый блок, а случайный (getAt(Phaser.Math.Between(0, 11))).
2. Реализуйте перетаскивание (drag) спрайта с автоматическим вызовом bringToTop() при начале переноса.
3. Создайте две независимые группы и попробуйте управлять порядком между ними через свойство depth.
4. Сымитируйте стопку карт: при клике на карту в середине колоды поднимите ее и все карты выше на новую позицию по Y, а затем вызовите bringToTop() только для кликнутой карты.
