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

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

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

Живой запуск

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

Исходный код


class Controller extends Phaser.Scene
{
    constructor ()
    {
        super({ key: 'controller' });
    }

    preload ()
    {
        // this.load.setBaseURL('https://cdn.phaserfiles.com/v385');
        this.load.script('demo', 'src/scenes/external scene/Demo.js');
    }

    create ()
    {
        var clone = 0;

        this.time.addEvent({ delay: 2000, callback: function () {

            this.scene.add('demo' + clone, Demo, true);
            clone++;

        }, callbackScope: this, repeat: 2 });
    }
}

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

const game = new Phaser.Game(config);

Архитектура примера: Главная сцена-контроллер

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

Основная сцена Controller указана как единственная в массиве scene при создании игры. Именно она будет запущена первой и будет отвечать за дальнейшую логику.

const config = {
    type: Phaser.WEBGL,
    width: 800,
    height: 600,
    parent: 'phaser-example',
    scene: [ Controller ] // Запускается только Controller
};

const game = new Phaser.Game(config);

Динамическая загрузка скрипта с классом сцены

Класс целевой сцены (Demo) не загружается изначально. Вместо этого мы динамически подгружаем его JavaScript-файл в методе preload() сцены-контроллера. Для этого используется метод this.load.script().

Важный нюанс: после такой загрузки класс Demo становится доступен глобально, и мы сможем ссылаться на него при создании сцены.

preload ()
{
    // Динамически загружаем файл со скриптом сцены Demo
    this.load.script('demo', 'src/scenes/external scene/Demo.js');
}

Создание сцен по таймеру с помощью Time Events

Сердце логики находится в методе create(). Мы используем систему событий времени Phaser (this.time.addEvent), чтобы с заданным интервалом создавать и запускать новые экземпляры сцены.

1.  **Таймер**: Событие настраивается на задержку в 2000 мс, повторяется 2 раза (итого будет создано 3 сцены).
2.  **Создание сцены**: В коллбэке используется `this.scene.add()`. Этот метод регистрирует новую сцену в менеджере сцен Phaser. Ключ сцены генерируется динамически (`'demo' + clone`), чтобы каждый экземпляр был уникальным.
3.  **Немедленный запуск**: Третий параметр `true` в `this.scene.add()` указывает, что сцену нужно не только зарегистрировать, но и сразу запустить.
create ()
{
    var clone = 0;

    this.time.addEvent({
        delay: 2000,
        callback: function () {
            // Регистрируем и сразу запускаем новую сцену
            this.scene.add('demo' + clone, Demo, true);
            clone++;
        },
        callbackScope: this,
        repeat: 2
    });
}

Ключевые API Phaser в этом примере

Для успешного использования этого паттерна важно понимать несколько ключевых методов API Phaser 3:

*   `this.load.script(key, url)`: Загружает внешний JavaScript-файл и делает его содержимое доступным глобально.
*   `this.time.addEvent(config)`: Создаёт повторяющееся или отложенное событие. Конфиг включает `delay`, `callback`, `callbackScope` и `repeat`.
*   `this.scene.add(key, sceneClass, autoStart)`: Основной метод для динамической регистрации сцены. `key` — уникальный строковый идентификатор, `sceneClass` — ссылка на класс (в нашем случае глобальный `Demo`), `autoStart` — флаг немедленного запуска.

Использование callbackScope: this в конфиге таймера критически важно — оно гарантирует, что внутри коллбэка this будет указывать на экземпляр сцены Controller, и мы сможем корректно вызвать this.scene.add().

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

Динамическое создание сцен — мощный инструмент в Phaser 3 для построения сложной игровой логики. Разобранный паттерн позволяет отложить загрузку ресурсов и инициализацию до нужного момента, управлять порядком запуска уровней или мини-игр. Для экспериментов попробуйте: 1. Загружать сцены не по таймеру, а по клику игрока. 2. Передавать данные в новую сцену через её конструктор или метод init(). 3. Останавливать (this.scene.stop()) или переключаться (this.scene.start()) между динамически созданными сценами.