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

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

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

Живой запуск

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

Исходный код


class SceneA extends Phaser.Scene {

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

    create ()
    {
        let graphics = this.add.graphics();

        graphics.fillStyle(0xff3300, 1);

        graphics.fillRect(100, 200, 600, 300);
        graphics.fillRect(100, 100, 100, 100);

        this.add.text(120, 110, 'A', { font: '96px Courier', fill: '#000000' });
    }
}

class SceneB extends Phaser.Scene {

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

    create ()
    {
        let graphics = this.add.graphics();

        graphics.fillStyle(0xff9933, 1);

        graphics.fillRect(100, 200, 600, 300);
        graphics.fillRect(200, 100, 100, 100);

        this.add.text(220, 110, 'B', { font: '96px Courier', fill: '#000000' });
    }
}

class SceneC extends Phaser.Scene {

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

    create ()
    {
        let graphics = this.add.graphics();

        graphics.fillStyle(0xffcc33, 1);

        graphics.fillRect(100, 200, 600, 300);
        graphics.fillRect(300, 100, 100, 100);

        this.add.text(320, 110, 'C', { font: '96px Courier', fill: '#000000' });
    }
}

let config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#392542',
    parent: 'phaser-example',
    scene: [ SceneA, SceneB, SceneC ]
};

let game = new Phaser.Game(config);

Базовый пример: статический порядок

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

scene: [ SceneA, SceneB, SceneC ]

Именно этот массив определяет порядок, в котором сцены будут созданы (вызван их метод create()), а также порядок их отрисовки на экране. Сцены отрисовываются последовательно, одна поверх другой. В данном примере SceneA будет на заднем плане, SceneB поверх нее, а SceneC — на самом верху. Поэтому на экране мы видим только прямоугольники и букву от SceneC, так как они перекрывают графику предыдущих сцен.

Этот подход прост, но негибок. Порядок зафиксирован на этапе конфигурации и не может быть изменен во время выполнения игры.

Ключевые свойства: active, visible и sleep

Каждая сцена в Phaser управляется набором булевых свойств. В конструкторе каждой сцены в примере явно установлено свойство active: true.

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

Давайте разберемся, что это означает: - **active**: Если true, сцена получает обновления (вызывается ее метод update()). Не влияет на отрисовку. - **visible**: Если true, сцена отрисовывается. По умолчанию имеет значение true. - **sleep**: Противоположность active. Если сцена в состоянии сна (sleep: true), ее метод update не вызывается.

В примере все три сцены активны и видны. Они одновременно обновляются и отрисовываются, что приводит к их наложению. Управляя этими свойствами динамически, мы можем менять поведение сцен.

Динамическое управление сценами через менеджер

Настоящая сила раскрывается при использовании менеджера сцен (this.scene). Он доступен внутри любой сцены и предоставляет методы для управления порядком и состоянием.

**Чтобы переместить сцену на передний план (сделать ее последней в порядке отрисовки), используйте:**

this.scene.moveAbove('SceneA', 'SceneC');
// Или
this.scene.sendToBack('SceneC');
this.scene.bringToTop('SceneA');

**Чтобы запустить или остановить сцену:**

// Запустить сцену (добавить в список активных/видимых)
this.scene.launch('SceneD');
// Остановить сцену (удалить из списка, но не уничтожать)
this.scene.stop('SceneB');
// Переключить видимость
this.scene.setVisible(false, 'SceneC');

Эти вызовы можно привязать к событиям ввода, таймерам или игровой логике, создавая интерактивные переходы.

Практический паттерн: переключение сцен по клику

Давайте модифицируем SceneC, чтобы по клику она скрывала себя и показывала сцену, находящуюся под ней. Добавим в create() метод SceneC обработчик ввода.

create ()
{
    let graphics = this.add.graphics();
    graphics.fillStyle(0xffcc33, 1);
    graphics.fillRect(100, 200, 600, 300);
    graphics.fillRect(300, 100, 100, 100);
    this.add.text(320, 110, 'C', { font: '96px Courier', fill: '#000000' });

    // Делаем сцену интерактивной
    this.input.on('pointerdown', function () {
        // Скрываем текущую сцену
        this.scene.setVisible(false);
        // Останавливаем ее обновление (опционально, для экономии ресурсов)
        this.scene.sleep();
        // Пытаемся "разбудить" сцену под ней. Нужно знать ее ключ.
        // Предположим, мы хотим активировать SceneB.
        let sceneB = this.scene.get('SceneB');
        if (sceneB) {
            sceneB.setVisible(true);
            sceneB.wake(); // Пробуждаем, если она спала
            // Или перемещаем на верх, если это требуется
            // this.scene.bringToTop('SceneB');
        }
    }, this);
}

Этот паттерн лежит в основе создания меню, диалоговых окон и сложных UI-стеков.

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

Использование статического массива сцен — лишь отправная точка. Динамическое управление через this.scene — мощный инструмент для создания живой, отзывчивой игры. Экспериментируйте: создайте систему модальных окон, реализуйте плавные переходы между уровнями (transition), организуйте "кучу" игровых интерфейсов (HUD, меню паузы, инвентарь) как отдельные сцены, которыми можно жонглировать. Помните, что методы pause, resume, switch также в вашем арсенале для построения сложной архитектуры.