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

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

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

Живой запуск

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

Исходный код


const demo = new Phaser.Scene('Demo');
demo.preload = function () {

    this.load.image('face', 'assets/pics/bw-face.png');

};
demo.create = function () {

    console.log(this.sys.settings.key, 'is alive');

    this.add.image(400, 300, 'face');

    this.scene.launch('Test');

};

const test = new Phaser.Scene('Test');
test.preload = function () {

    this.load.image('barbarian', 'assets/pics/barbarian-loading.png');

};
test.create = function () {

    console.log(this.sys.settings.key, 'is alive');

    this.add.image(400, 300, 'barbarian').setScale(0.5);
}

const config = {
    type: Phaser.CANVAS,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: [ demo, test ]
};

const game = new Phaser.Game(config);

Создание сцен через конструктор `new Phaser.Scene`

В отличие от распространённого подхода с передачей классов в конфигурацию игры, данный пример демонстрирует создание сцен как объектов. Каждая сцена создается с помощью конструктора new Phaser.Scene, и ей сразу присваивается уникальный строковый ключ. Этот ключ позже используется для управления сценой.

const demo = new Phaser.Scene('Demo');
const test = new Phaser.Scene('Test');

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

Настройка и жизненный цикл сцены Demo

Первая сцена, Demo, загружает одно изображение и, после создания, запускает вторую сцену.

В методе preload используется this.load.image для загрузки ассета. Важно помнить, что this внутри этих методов ссылается на саму сцену, предоставляя доступ к её системам.

demo.preload = function () {
    this.load.image('face', 'assets/pics/bw-face.png');
};

В методе create сцена выводит в консоль свой ключ (доступный через this.sys.settings.key) и добавляет загруженное изображение в центр экрана. Затем с помощью this.scene.launch('Test') она запускает вторую сцену.

demo.create = function () {
    console.log(this.sys.settings.key, 'is alive');
    this.add.image(400, 300, 'face');
    this.scene.launch('Test');
};

Метод launch запускает сцену с ключом 'Test', не останавливая текущую. Обе сцены теперь будут выполняться параллельно.

Параллельная работа сцены Test

Вторая сцена, Test, создается и настраивается аналогичным образом. Она загружает своё собственное изображение и выводит его с измененным масштабом.

const test = new Phaser.Scene('Test');
test.preload = function () {
    this.load.image('barbarian', 'assets/pics/barbarian-loading.png');
};
test.create = function () {
    console.log(this.sys.settings.key, 'is alive');
    this.add.image(400, 300, 'barbarian').setScale(0.5);
}

Обратите внимание, что сцены загружают ресурсы независимо друг от друга. Ресурсы, загруженные в сцене Demo, не доступны в сцене Test и наоборот, если не используется общий кэш. После вызова this.scene.launch('Test') из сцены Demo, Phaser автоматически вызовет методы preload и create для сцены Test. Обе сцены активны и отрисовываются: изображение из Test будет нарисовано поверх изображения из Demo, так как она была запущена позже.

Конфигурация игры и регистрация сцен

Чтобы сцены стали частью игры, их необходимо передать в конфигурацию игры в свойстве scene. В данном случае передается массив созданных экземпляров [demo, test].

const config = {
    type: Phaser.CANVAS,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: [ demo, test ] // Экземпляры сцен передаются напрямую
};

const game = new Phaser.Game(config);

Phaser запускает первую сцену из массива (demo) автоматически. Порядок в массиве определяет порядок вызова некоторых системных событий, но не порядок отрисовки — он зависит от порядка запуска сцен и их настроек. Важно: сцена, запущенная первой (в данном случае demo), считается активной, и её методы обновления (update) будут вызываться.

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

Использование экземпляров сцен, созданных через new Phaser.Scene(), даёт прямой контроль над их жизненным циклом и позволяет гибко управлять их запуском и остановкой. Для экспериментов попробуйте: изменить порядок сцен в массиве конфигурации; запустить сцену Test с задержкой, используя this.time.delayedCall; или управлять сценами через меню, останавливая одну и запуская другую с помощью методов this.scene.stop() и this.scene.start().