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

В Phaser 3 сцены по умолчанию рендерятся в порядке их создания. Но что, если нужно динамически менять этот порядок во время выполнения игры? Например, чтобы вывести диалоговое окно поверх игрового мира или временно скрыть интерфейс. Именно для этого в API сцен существуют методы `moveAbove` и `moveBelow`. Эта статья покажет, как использовать эти методы для контроля визуального стека сцен, что особенно полезно при создании сложных интерфейсов и многослойных игровых миров.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Controller extends Phaser.Scene {

    constructor ()
    {
        super({ key: 'Controller', active: true });
    }

    create ()
    {
        this.input.on('pointerdown', function (pointer) {
            // this.scene.moveBelow('SceneA', 'SceneB');
            // this.scene.moveBelow('SceneB', 'SceneA');
            // this.scene.moveAbove('SceneB', 'SceneA');
            this.scene.moveAbove('SceneA', 'SceneB');
        }, this);
    }
}

class SceneA extends Phaser.Scene {

    constructor ()
    {
        super({ key: 'SceneA', active: true });
    }

    create ()
    {
        this.add.rectangle(340, 300, 64, 64, 0xff33cc);
        this.add.text(340, 300, 'A');
    }
}

class SceneB extends Phaser.Scene {

    constructor ()
    {
        super({ key: 'SceneB', active: true });
    }

    create ()
    {
        this.add.rectangle(380, 300, 64, 64, 0xbbb3cc);
        this.add.text(380, 300, 'B');
    }
}

let config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: [ Controller, SceneA, SceneB ]

    // When left mouse is clicked, SceneA and SceneB will be swapped regardless of the order
};

let game = new Phaser.Game(config);

Проблема: статический порядок рендеринга сцен

По умолчанию Phaser рендерит сцены в том порядке, в котором они перечислены в массиве scene конфигурации игры. В примере выше сначала рендерится Controller, затем SceneA, и, наконец, SceneB. Визуально это означает, что SceneB будет отображаться поверх SceneA, так как она добавлена позже.

Этот порядок фиксирован на этапе инициализации. Если вашей игре требуется, чтобы один слой (например, UI) иногда оказывался позади другого (например, полноэкранного меню), простого порядка из конфига недостаточно. Нужен механизм для перестановки сцен в стеке рендеринга «на лету».

Решение: методы moveAbove и moveBelow

Phaser предоставляет два метода для управления порядком сцен:

*   `this.scene.moveAbove(keyA, keyB)`: Перемещает сцену с ключом `keyA` **выше** сцены с ключом `keyB` в стеке рендеринга.
*   `this.scene.moveBelow(keyA, keyB)`: Перемещает сцену с ключом `keyA` **ниже** сцены с ключом `keyB`.

Ключ (key) — это строка, которую вы задали при создании сцены в конструкторе (super({ key: 'SceneA' })). Эти методы вызываются из контекста любой активной сцены, обращаясь к глобальному менеджеру сцен через this.scene.

В исходном примере метод вызывается при клике мыши. Давайте разберем его работу.

Разбор примера кода

В примере создаются три сцены: Controller, SceneA и SceneB. Controller служит для обработки ввода, в то время как SceneA и SceneB отрисовывают два цветных квадрата с буквами.

Поскольку SceneB добавлена в массив последней, она изначально будет поверх SceneA. В сцене Controller на событие клика мыши (pointerdown) назначен обработчик.

this.input.on('pointerdown', function (pointer) {
    this.scene.moveAbove('SceneA', 'SceneB');
}, this);

При клике выполняется команда this.scene.moveAbove('SceneA', 'SceneB'). Это означает: «Перемести сцену 'SceneA' выше сцены 'SceneB'». В результате квадрат 'A' (из SceneA) окажется поверх квадрата 'B' (из SceneB).

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

Практическое применение и нюансы

Эти методы незаменимы при работе со слоями интерфейса: 1. **Диалоговые окна:** Чтобы показать окно поверх всего, включая другие элементы UI, переместите сцену с диалогом выше всех остальных. 2. **Пауза и меню:** Сцена с меню паузы может быть перемещена поверх игровой сцены, а затем возвращена обратно. 3. **Эффекты затемнения:** Сцена с полупрозрачным чёрным прямоугольником может быть временно поднята наверх для создания эффекта затемнения.

// Показать меню паузы поверх игры
this.scene.moveAbove('PauseMenu', 'GameScene');

// Скрыть меню, вернув его под игровую сцену
this.scene.moveBelow('PauseMenu', 'GameScene');

Обратите внимание, что методы работают только с активными сценами. Они не запускают и не останавливают сцены, а лишь меняют их порядок отрисовки. Также невозможно переместить сцену выше или ниже самой себя — такое действие будет проигнорировано.

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

Методы moveAbove и moveBelow — это мощный, но простой инструмент для динамического управления визуальной иерархией вашей игры. Они позволяют создавать гибкие интерфейсы и многослойную графику, реагирующую на действия игрока. Для экспериментов попробуйте: создать более двух накладывающихся сцен и реализовать циклическое переключение их порядка; привязать управление порядком не к клику, а к игровым событиям (сбор предмета, получение урона); комбинировать эти методы с настройками видимости (setVisible) и активности сцен для ещё более сложного контроля.