Параллельные сцены и наложение сцен

Phaser — это мощная библиотека для разработки 2D-игр на JavaScript, которая предоставляет гибкую систему сцен (Scenes). Каждая сцена инкапсулирует свой цикл жизни, объекты, логику и обработку событий. Важная особенность Phaser заключается в возможности параллельного запуска нескольких сцен, что позволяет создавать сложные интерфейсы, наложения HUD, меню и игровые уровни, работающие одновременно.

Сцены могут существовать одновременно, обновляться независимо и взаимодействовать друг с другом, сохраняя при этом собственное состояние.

let config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    scene: [MainScene, HUDScene]
};

let game = new Phaser.Game(config);

В этом примере MainScene отвечает за игровой мир, а HUDScene — за отображение очков, жизней и другой информации поверх игрового поля.


Создание и управление сценами

Добавление и запуск сцен

Сцены могут быть добавлены несколькими способами: через конфигурацию при инициализации Phaser.Game или динамически с помощью методов this.scene.add и this.scene.launch.

this.scene.add('InventoryScene', InventoryScene, false);
this.scene.launch('InventoryScene');
  • add — добавляет сцену в менеджер сцен без её автоматического запуска.
  • launch — запускает сцену параллельно с текущей.
  • start — полностью запускает сцену, останавливая текущую (не параллельно).

Порядок рендеринга

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

this.scene.launch('OverlayScene'); // поверх основной сцены

Для контроля над порядком можно использовать методы bringToTop и sendToBack:

this.scene.bringToTop('HUDScene');
this.scene.sendToBack('BackgroundScene');

Наложение сцен

Наложение сцен позволяет создавать интерфейсы, которые не мешают основной логике игры. Например, панель меню, индикаторы здоровья, карты или диалоговые окна.

Пример структуры с наложением:

  1. MainScene — игровой уровень, обрабатывает физику, игрока и врагов.
  2. HUDScene — отображает очки, здоровье и таймер.
  3. MenuScene — вызывается по паузе и накладывается поверх MainScene, блокируя взаимодействие с игровой сценой.
this.scene.launch('HUDScene'); 
this.scene.pause('MainScene'); // для паузы при открытии меню
this.scene.launch('MenuScene'); 

Связь между сценами

Сцены могут обмениваться данными через EventEmitter:

// В MainScene
this.events.emit('scoreChanged', 100);

// В HUDScene
this.scene.get('MainScene').events.on('scoreChanged', (score) => {
    this.scoreText.setText(`Score: ${score}`);
});

Использование событий гарантирует, что сцены остаются слабосвязанными, а их жизненные циклы независимыми.


Жизненный цикл параллельных сцен

Phaser сцены имеют стандартные методы жизненного цикла:

  • init(data) — инициализация, передача данных между сценами.
  • preload() — загрузка ресурсов.
  • create() — создание объектов сцены.
  • update(time, delta) — игровой цикл обновления, вызывается каждый кадр.
  • shutdown() / destroy() — освобождение ресурсов и остановка сцены.

При параллельном запуске несколько сцен могут одновременно иметь активный метод update, что требует внимания к производительности и синхронизации данных.


Управление видимостью и интерактивностью

Сцены могут быть видимыми или скрытыми и активными или приостановленными независимо друг от друга:

this.scene.setVisible(false); // скрыть сцену
this.scene.setActive(false);  // приостановить обновления

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


Оптимизация параллельных сцен

При работе с несколькими сценами важно учитывать нагрузку на рендер и обработку логики:

  1. Минимизировать количество активных объектов в фоне.
  2. Приостанавливать сцены, не требующие обновлений, с помощью scene.pause.
  3. Использовать слабосвязанные события вместо прямых ссылок между сценами.
  4. Контролировать порядок рендеринга, чтобы избежать лишнего перерисовывания слоёв.

Практический пример: игра с наложением интерфейса и меню

class MainScene extends Phaser.Scene {
    constructor() {
        super('MainScene');
    }
    create() {
        this.player = this.add.sprite(400, 300, 'player');
        this.scene.launch('HUDScene');
    }
    update() {
        // Логика движения игрока
    }
}

class HUDScene extends Phaser.Scene {
    constructor() {
        super('HUDScene');
    }
    create() {
        this.scoreText = this.add.text(10, 10, 'Score: 0', { fontSize: '32px', fill: '#fff' });
        this.scene.get('MainScene').events.on('scoreChanged', (score) => {
            this.scoreText.setText(`Score: ${score}`);
        });
    }
}

В этом примере HUDScene реагирует на события MainScene, остаётся поверх игрового поля и обновляет интерфейс в реальном времени, не вмешиваясь в логику движения игрока.


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