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

В Phaser 3 сцены управляются в виде списка, и их порядок напрямую влияет на рендеринг и обработку ввода. Метод `moveUp()` позволяет динамически менять позицию активной сцены в этом списке. Эта техника полезна для создания сложных UI-переходов, модальных окон, пауз или систем приоритетов, когда одной сцене нужно временно оказаться поверх других без её полной остановки.

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

Живой запуск

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

Исходный код


class DemoA extends Phaser.Scene
{
    constructor ()
    {
        super({ key: 'demoA', active: true });
    }

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('picA', 'assets/pics/lance-overdose-loader-eye.png');
    }

    create ()
    {
        this.add.image(400, 300, 'picA');

        this.input.on('pointerup', function ()
        {

            this.scene.moveUp();

        }, this);
    }
}

class DemoB extends Phaser.Scene
{
    constructor ()
    {
        super({ key: 'demoB', active: true });
    }

    preload ()
    {
        // this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('picB', 'assets/pics/sukasuka-chtholly.png');
    }

    create ()
    {
        this.add.image(400, 500, 'picB');
    }
}

class DemoC extends Phaser.Scene
{
    constructor ()
    {
        super({ key: 'demoC', active: true });
    }

    preload ()
    {
        // this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('picC', 'assets/pics/titan-mech.png');
    }

    create ()
    {
        this.add.image(300, 300, 'picC');
    }
}

const config = {
    type: Phaser.WEBGL,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: [ DemoA, DemoB, DemoC ]
};

const game = new Phaser.Game(config);

Понимание порядка сцен

Когда вы передаёте массив классов сцен в конфигурацию игры, Phaser создаёт их экземпляры и помещает в управляемый список. Порядок в этом списке определяет две ключевые вещи:

1. **Отрисовка (рендеринг):** Сцены рендерятся последовательно, от начала списка к концу. Таким образом, сцена, находящаяся позже в списке, будет отрисована поверх предыдущих. 2. **Обработка ввода:** По умолчанию, если несколько сцен обрабатывают один и тот же тип ввода (например, клик), событие будет передано им всем, начиная с верхней (последней в списке) сцены.

Изначальный порядок в нашем примере задаётся массивом [ DemoA, DemoB, DemoC ]. Это значит, что сначала отрисуется DemoA, затем поверх неё DemoB, и, наконец, сверху всего DemoC.

const config = {
    type: Phaser.WEBGL,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: [ DemoA, DemoB, DemoC ] // Исходный порядок сцен
};

Как работает scene.moveUp()

Метод moveUp() принадлежит объекту SceneManager и вызывается для текущей (активной) сцены через this.scene. Его задача — переместить текущую сцену на одну позицию выше в внутреннем списке управления сценами.

В контексте нашего примера, когда вы кликаете (событие pointerup) в сцене DemoA, происходит следующее:

1. Исходный порядок: [DemoA, DemoB, DemoC]. 2. Вызывается this.scene.moveUp() для DemoA. 3. DemoA меняется местами со следующей за ней сценой в списке, то есть с DemoB. 4. Новый порядок становится: [DemoB, DemoA, DemoC].

Код, который это реализует, находится в методе create сцены DemoA:

create ()
{
    this.add.image(400, 300, 'picA');

    this.input.on('pointerup', function ()
    {
        this.scene.moveUp(); // Перемещает DemoA вверх по списку
    }, this);
}

Важно отметить, что moveUp() работает с **активной** сценой, из которой он вызван. Нельзя извне переместить неактивную сцену, не сделав её активной предварительно.

Визуальный результат и практическое применение

После вызова moveUp() сцена DemoA (с изображением глаза) моментально окажется поверх сцены DemoB (с аниме-девушкой), но всё ещё под сценой DemoC (с мехом). Визуально это выглядит как мгновенная смена слоёв.

Почему это полезно на практике?

* **Динамические HUD/UI:** Вы можете держать UI-сцену внизу списка и поднимать её наверх только когда нужно показать сообщение или меню. * **Система паузы:** Сцена с меню паузы может быть добавлена в конец списка, а по нажатию кнопки "Продолжить" — опущена вниз, чтобы игровая сцена снова оказалась наверху для обработки ввода. * **Управление фокусом:** В играх с несколькими игровыми областями (например, карта и диалоги) вы можете переключать фокус, меняя порядок сцен, вместо их остановки и перезапуска.

Обратите внимание, что в примере сцены DemoB и DemoC не содержат кода для обработки ввода. Они просто отрисовывают изображения. Вся логика перемещения заключена в DemoA.

Семейство методов для управления порядком

moveUp() — не единственный метод для управления позицией сцены. SceneManager предоставляет целый набор методов:

* moveDown(): Перемещает сцену на одну позицию вниз по списку. * moveAbove(key): Перемещает сцену **над** сценой с указанным ключом. * moveBelow(key): Перемещает сцену **под** сцену с указанным ключом. * sendToBack(): Перемещает сцену в самый низ списка (первой для отрисовки). * bringToTop(): Перемещает сцену на самый верх списка (последней для отрисовки).

Например, чтобы мгновенно переместить текущую сцену поверх всех остальных, можно использовать bringToTop():

this.input.on('pointerup', function ()
{
    this.scene.bringToTop(); // DemoA окажется поверх DemoC
}, this);

Эти методы дают полный контроль над стеком рендеринга сцен в реальном времени.

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

Метод moveUp() и его аналоги — это мощный, но часто упускаемый из виду инструмент для управления визуальным стеком и логикой приложения в Phaser 3. Они позволяют создавать динамические интерфейсы без необходимости скрывать/показывать объекты вручную или управлять их глубиной (depth) в рамках одной сцены. **Идеи для экспериментов:** 1. Создайте сцену-оверлей с полупрозрачным чёрным фоном и текстом "ПАУЗА". Реализуйте систему, где нажатие ESC поднимает эту сцену наверх, а повторное нажатие — опускает вниз. 2. Реализуйте систему уведомлений: при событии в игре (подбор предмета) поднимайте небольшую UI-сцену с сообщением наверх, а через 2 секунды автоматически возвращайте её вниз. 3. Создайте несколько интерактивных сцен (с обработкой кликов) и поэкспериментируйте с moveUp()/moveDown(), чтобы увидеть, как меняется приоритет получения событий ввода.