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

При создании сложных игр с интерфейсами, меню или наложениями часто требуется динамически менять порядок отрисовки сцен. Стандартный порядок, заданный в конфигурации, не всегда подходит для интерактивных сценариев. В этой статье разберем, как использовать метод `scene.bringToTop()` для управления стэком сцен на примере из официальной документации. Понимание работы со сценами — ключ к созданию чистого и управляемого кода в Phaser. Мы рассмотрим, как правильно инициализировать несколько активных сцен и программно выводить нужную из них на передний план, что особенно полезно для реализации пауз, диалоговых окон или сложных UI/эффектов.

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

Живой запуск

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

Исходный код


//  Needless to say, RICK AND MORTY is a trademark of Cartoon Network, Inc.,

class Controller extends Phaser.Scene {

    constructor ()
    {
        super('Controller');
    }

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

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

        //  This will bring the Logo Scene to the top of the Scene List
        this.scene.bringToTop('Logo');
    }

}

class Rick extends Phaser.Scene {

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

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

    create ()
    {
        this.add.image(750, 600, 'rick').setOrigin(1);
    }
}

class Morty extends Phaser.Scene {

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

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

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

class Logo extends Phaser.Scene {

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

    preload ()
    {
        // this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('logo', 'assets/pics/rick-and-morty-logo.png');
    }

    create ()
    {
        this.add.image(400, 450, 'logo');
    }
}

let config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: [ Controller, Logo, Morty, Rick ]
};

let game = new Phaser.Game(config);

Анатомия примера: четыре сцены в одном проекте

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

Ключевой момент — настройка сцен в массиве scene конфигурации игры. Порядок в этом массиве определяет начальный порядок отрисовки (снизу вверх). Однако, если сцены созданы с флагом active: true, они рендерятся одновременно, и их порядок в стеке можно менять динамически.

let config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: [ Controller, Logo, Morty, Rick ]
};

Создание сцен: флаг active и ключ key

Три сцены (Logo, Morty, Rick) создаются с одинаковыми параметрами в конструкторе. Параметр active: true указывает, что сцена должна запуститься сразу же при старте игры. Параметр key — это уникальный строковый идентификатор сцены, по которому мы сможем к ней обращаться из других сцен.

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

Сцена Controller объявлена иначе. Она не активна изначально и будет запущена явно, так как указана первой в массиве конфигурации. Ее роль — управление порядком других сцен.

Метод bringToTop: как вывести сцену на передний план

Вся магия управления порядком происходит в сцене Controller. В ее методе create() после загрузки фона вызывается одна критически важная команда.

create ()
{
    this.add.image(400, 300, 'bg');
    //  This will bring the Logo Scene to the top of the Scene List
    this.scene.bringToTop('Logo');
}

Метод this.scene.bringToTop('Logo') ищет в системе сцен экземпляр с ключом 'Logo' и перемещает его на самый верх стека отрисовки. Это означает, что все графические объекты сцены Logo (в данном случае изображение с логотипом) будут отрисованы поверх всех объектов сцен, которые находятся ниже в стеке (Morty и Rick). Без этого вызова логотип был бы скрыт за изображениями персонажей.

Визуальный результат и порядок слоев

Давайте представим итоговый порядок сцен после выполнения кода: 1. **Нижний слой:** Controller (фиолетовый фон). Он был запущен первым. 2. **Средний слой:** Rick и Morty. Они активны с самого начала и отрисованы в порядке, обратном массиву конфигурации (сначала Rick, потом Morty, но так как они на одном уровне, важен только факт, что они ниже Logo). 3. **Верхний слой:** Logo. Благодаря вызову bringToTop, эта сцена оказалась поверх всех, и ее логотип теперь виден целиком.

Если убрать строку с bringToTop, логотип будет отрисован согласно начальному порядку из массива scene, то есть, скорее всего, окажется под персонажами и будет частично или полностью скрыт.

Практическое применение: меню, диалоги, окна

Метод bringToTop — это не просто инструмент для статичной композиции, а основа для интерактивности.

* **Всплывающее меню паузы:** У вас может быть сцена Game (игровой мир) и сцена PauseMenu (меню). При нажатии ESC вы запускаете сцену PauseMenu и вызываете для нее bringToTop, чтобы она перекрыла игру. * **Диалоговые окна:** Создайте сцену Dialog. Каждый раз при начале диалога запускайте ее и выводите на передний план поверх игровой сцены. * **Система уведомлений:** Сцена Notification может появляться поверх всего интерфейса для показа важных сообщений.

Важно помнить, что bringToTop работает только с уже запущенными (active) сценами. Для неактивных сцен сначала используйте this.scene.launch('YourSceneKey').

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

Динамическое управление порядком сцен через bringToTop() — мощный механизм в Phaser 3 для создания многослойных интерфейсов и игровых состояний. Он позволяет разделять логику разных частей игры (UI, мир, эффекты) по разным сценам, сохраняя при этом полный контроль над их видимостью. **Идеи для экспериментов:** 1. Добавьте в сцену Controller обработчик клика мыши, который по очереди выводит на передний план сцены Rick, Morty и Logo. 2. Создайте сцену-«затемнитель» (Dim) с полупрозрачным черным прямоугольником. Используйте bringToTop, чтобы затемнять фон при показе меню паузы, создавая визуальную глубину. 3. Изучите другие методы управления сценами: sendToBack(), moveUp(), moveDown() — и создайте простой визуальный редактор порядка слоев.