О чем этот пример
Часто в играх требуется создавать новые игровые состояния или уровни "на лету", в ответ на действия игрока. В Phaser сцены (Scenes) — это основа организации кода. В этой статье мы разберем, как добавить новую сцену прямо во время выполнения игры и передать в нее начальные параметры. Этот подход полезен для создания модульных уровней, всплывающих окон или смены игровых режимов без предварительной загрузки всех сцен.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class MyScene extends Phaser.Scene {
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('face', 'assets/pics/bw-face.png');
}
create (data)
{
this.face = this.add.image(data.x, data.y, 'face');
}
}
class BootScene extends Phaser.Scene {
create ()
{
this.add.text(0, 0, 'Click to add new Scene');
this.input.once('pointerdown', function () {
this.scene.add('myScene', MyScene, true, { x: 400, y: 300 });
}, this);
}
}
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: BootScene
};
var game = new Phaser.Game(config);
Подготовка сцены-приемника
Сначала создадим сцену, которая будет добавлена динамически. Ключевой момент — метод create этой сцены должен принимать параметр data. Через этот объект мы передадим данные из вызывающей сцены.
В данном примере сцена MyScene загружает одно изображение и в методе create размещает его по координатам, переданным в data.x и data.y.
class MyScene extends Phaser.Scene {
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('face', 'assets/pics/bw-face.png');
}
create (data)
{
this.face = this.add.image(data.x, data.y, 'face');
}
}
Запуск и инициирование добавления
Игра начинается со сцены BootScene. В ее методе create мы выводим текст-инструкцию и настраиваем обработчик клика мыши. Обратите внимание на использование this.input.once — событие сработает только один раз.
class BootScene extends Phaser.Scene {
create ()
{
this.add.text(0, 0, 'Click to add new Scene');
this.input.once('pointerdown', function () {
// Код для добавления сцены будет здесь
}, this);
}
}
Контекст this в колбэке сохраняется благодаря третьему аргументу this в вызове this.input.once. Это важно, чтобы внутри функции-обработчика this указывал на текущую сцену (BootScene), а не на глобальный объект.
Динамическое добавление сцены
Внутри обработчика клика мы вызываем метод this.scene.add. Это мощный API менеджера сцен Phaser.
this.scene.add('myScene', MyScene, true, { x: 400, y: 300 });
Разберем аргументы:
1. `'myScene'` — уникальный ключ (идентификатор) для новой сцены.
2. `MyScene` — класс (конструктор) сцены, которую нужно создать.
3. `true` — флаг, указывающий, что сцену нужно запустить сразу после добавления (автозапуск). Если передать `false`, сцена будет добавлена в менеджер, но для ее запуска потребуется отдельный вызов `this.scene.start('myScene')`.
4. `{ x: 400, y: 300 }` — данные, которые будут переданы в метод `create` добавляемой сцены (`MyScene`). В нашем примере это объект с координатами.
Конфигурация игры и итог
Стандартная конфигурация игры указывает BootScene как стартовую сцену.
var config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: BootScene // Стартовая сцена
};
var game = new Phaser.Game(config);
В результате при клике на игровом поле из BootScene будет создана и запущена новая сцена MyScene. Изображение лица появится в координатах (400, 300), которые были переданы при добавлении. Исходная сцена BootScene продолжит работать, если ее не остановить явно.
Что попробовать дальше
Метод this.scene.add открывает путь к гибкой архитектуре игры. Вы можете создавать сцены по требованию, что экономит ресурсы при старте. Для экспериментов попробуйте
- Добавить несколько экземпляров одной и той же сцены с разными ключами и данными
- Не запускать сцену сразу (
false), а запустить ее позже по таймеру или другому событию - Передавать в данные не только координаты, но и, например, тип врага или сложность уровня
