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

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

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

Живой запуск

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

Исходный код


var SceneA = {
    key: 'SceneA',

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

    init: function init() {
        //  NOTE: Should yield `SceneB { ... }`, etc.
        console.info('SceneA init');
        console.log(this.scene.get('SceneB'));
        console.log(this.scene.get('SceneC'));
    },

    create: function create() {
        console.info('SceneA started.');
        // this.scene.launch('SceneB').launch('SceneC');
        this.scene.launch('SceneB');
    }
};

var SceneB = {
    key: 'SceneB',

    init: function init() {
        console.info('SceneB init.');
        setTimeout(
            () => {
                console.log(this.scene.get('SceneA'));
                console.log(this.scene.get('SceneB'));
                console.log(this.scene.get('SceneC'));
            },
            1000
        );
    },

    create: function create() {
        console.info('SceneB started.');
    }
};

class SceneC extends Phaser.Scene {

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

    create() {
        console.info('SceneC started.');
        this.add.image(160, 120, 'aqua_ball')
    }
}

var game = new Phaser.Game({
    type: Phaser.AUTO,
    parent: 'phaser-example',
    scene: [SceneA, SceneB, SceneC]
});

Что такое сцена в Phaser?

Сцена (Scene) — это основной контейнер для игровой логики, ресурсов и объектов. В Phaser можно запускать несколько сцен одновременно, что открывает возможности для параллельного выполнения разных задач.

В примере мы видим три сцены: SceneA, SceneB и SceneC. Они по-разному объявлены, что демонстрирует гибкость подхода.

Объявление сцен: объекты и классы

Phaser позволяет создавать сцены как простые объекты или как ES6-классы, расширяющие Phaser.Scene.

Объектный стиль используется для SceneA и SceneB:

var SceneA = {
    key: 'SceneA',
    preload: function preload() { ... },
    init: function init() { ... },
    create: function create() { ... }
};

Классовый стиль для SceneC:

class SceneC extends Phaser.Scene {
    constructor() {
        super('SceneC');
    }
    create() {
        ...
    }
}

Ключевое поле key (или передача строки в super()) — это уникальный идентификатор сцены, по которому можно получить доступ к её экземпляру через this.scene.get().

Запуск сцен: `launch` и порядок инициализации

Сцены регистрируются при создании игры, но не запускаются автоматически. Запуск происходит через метод launch().

В create() функции SceneA мы видим:

this.scene.launch('SceneB');

Это запускает SceneB параллельно с SceneA. Обе сцены теперь активны. Метод launch() можно чейнить для запуска нескольких сцен сразу.

Каждая сцена проходит свои жизненные циклы: init(), preload() (если есть), create(). Порядок вызова init() соответствует порядку сцен в массиве конфигурации игры, а create() вызывается только после запуска сцены через launch() или start().

Доступ к экземплярам сцен: метод `get()`

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

Например, в init() функции SceneA:

console.log(this.scene.get('SceneB'));

Это выведет объект сцены SceneB в консоль. В SceneB, через setTimeout, мы видим проверку доступности всех трёх сцен, что подтверждает их регистрацию в системе Phaser.

Важно: get() возвращает экземпляр сцены, но не гарантирует, что она уже была инициализирована (init) или создана (create).

Практическое применение параллельных сцен

Зачем запускать несколько сцен? Вот типичные сценарии: - **UI/HUD сцена**: отвечает за интерфейс (здоровье, очки), работает поверх игровой. - **Фоновая сцена**: управляет музыкой или фоновыми анимациями. - **Меню и пауза**: отдельная сцена для меню, которую можно запускать и останавливать, не трогая игровой мир.

В примере SceneC загружает спрайт 'aqua_ball', демонстрируя, что сцены могут использовать ресурсы, загруженные в других сценах (если они загружены глобально или через общий загрузчик), но в данном случае SceneC ничего не отобразит, так как спрайт загружается только в SceneA, а SceneC никогда не запускается.

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

Управление сценами в Phaser — мощный инструмент для организации кода. Вы можете запускать, останавливать, приостанавливать и переключать сцены, создавая сложные игровые состояния. **Идеи для экспериментов:** 1. Запустите SceneC из SceneA и разместите шары в разных координатах. 2. Добавьте в SceneB метод update() и попробуйте из него влиять на объекты в SceneA через this.scene.get(). 3. Создайте сцену-паузу, которая будет приостанавливать (this.scene.pause()) игровую сцену по нажатию клавиши.