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

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

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

Живой запуск

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

Исходный код


let config = {
    type: Phaser.AUTO,
    width: 1024,
    height: 600,
    parent: 'phaser-example',
    backgroundColor: '#000000',
    scene: [ Controller, SceneA, SceneB, SceneC, SceneD, SceneE, SceneF ]
};

let game = new Phaser.Game(config);

Сердце приложения: конфигурация игры

Все начинается с объекта конфигурации, который передается конструктору Phaser.Game. Это главный файл, точка входа в ваше приложение.

let config = {
    type: Phaser.AUTO,
    width: 1024,
    height: 600,
    parent: 'phaser-example',
    backgroundColor: '#000000',
    scene: [ Controller, SceneA, SceneB, SceneC, SceneD, SceneE, SceneF ]
};

let game = new Phaser.Game(config);

Ключевые параметры: * type: Phaser.AUTO позволяет движку самому выбрать рендерер (WebGL или Canvas). * width/height: устанавливают размер игрового холста. * parent: ID HTML-элемента, в который будет встроен холст. Если элемента с таким ID нет, он будет создан в <body>. * backgroundColor: цвет фона всего холста. * scene: **самая важная часть для нашего примера**. Это массив классов сцен. Первая сцена в массиве (Controller) будет запущена автоматически. Остальные сцены (SceneA...SceneF) зарегистрированы в системе и могут быть запущены позже.

Архитектура: одна главная, много подчиненных

Массив scene в конфиге загружает классы сцен в память движка. Однако запускается изначально только первая сцена — Controller. Она выступает в роли дирижера или менеджера.

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

// Внутри метода create() сцены Controller
this.scene.launch('SceneA');
this.scene.launch('SceneB');

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

Почему это работает? Менеджер сцен Phaser

Phaser внутренне управляет всеми сценами через объект ScenePlugin, доступный в любой сцене как this.scene. Этот плагин предоставляет мощный API для управления жизненным циклом.

Основные методы для работы с несколькими сценами:

// Запуск сцены. Если она уже запущена, метод не делает ничего.
this.scene.launch('SceneA');

// Приостановка сцены (останавливаются update, но сцена остается видимой).
this.scene.pause('SceneA');

// Возобновление приостановленной сцены.
this.scene.resume('SceneA');

// Полная остановка и выгрузка сцены.
this.scene.stop('SceneA');

// Передача данных в запускаемую сцену.
this.scene.launch('SceneB', { playerHealth: 100, level: 5 });

Данные, переданные вторым аргументом в launch(), будут доступны в методах init() и create() целевой сцены. Это основной способ коммуникации между сценами.

Практическое применение: HUD, пауза и мини-игры

Давайте рассмотрим реальные кейсы, где эта архитектура незаменима.

**1. Отдельный HUD:** Сцена игры (MainGame) отвечает за мир и персонажей. Сцена HUD отвечает за отображение здоровья, очков, карты. Она запускается параллельно и всегда поверх.

// В MainGame.js
create() {
    // ... создание мира ...
    this.scene.launch('HUD');
}

// Для обновления очков в HUD из MainGame:
this.scene.get('HUD').updateScore(100);

**2. Меню паузы:** При нажатии ESC вы запускаете сцену PauseMenu, которая приостанавливает основную игровую сцену.

// В MainGame.js, в обработчике клавиши ESC
pauseGame() {
    this.scene.pause(); // Приостанавливаем себя
    this.scene.launch('PauseMenu'); // Запускаем меню поверх
}

**3. Встроенная мини-игра:** Во время диалога можно запустить сцену мини-игры (например, взлом замка), а по её завершению — остановить и вернуться к диалогу.

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

Использование нескольких параллельных сцен — это мощный паттерн в Phaser, который помогает сохранять код чистым и организованным. Вы отделяете логику интерфейса от игрового мира, создаете сложные составные состояния игры и упрощаете отладку. **Идеи для экспериментов:** 1. Создайте систему модальных окон: каждая всплывашка — отдельная сцена, управляемая центральным DialogController. 2. Реализуйте плавные переходы между уровнями, где сцена-загрузчик анимирует прогресс, а старый уровень плавно затемняется. 3. Постройте сложный UI с несколькими независимыми панелями (инвентарь, журнал заданий, карта), где каждая панель — это своя сцена, которую можно включать и выключать по отдельности.