О чем этот пример
В Phaser сцены — это мощный инструмент для организации кода и игровой логики. Иногда вам нужно временно "переключиться" на другую игровую механику, например, на экран паузы, диалог или мини-игру, а затем плавно вернуться обратно. Именно для этого идеально подходят вложенные сцены (или под-игры). В этой статье мы разберем практический пример создания отдельной сцены `SubGame`, которая запускается из основной, отрисовывает свой уникальный контент и по клику возвращает игрока обратно. Вы узнаете, как управлять жизненным циклом сцен, передавать между ними данные и организовывать чистое взаимодействие.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class SubGame extends Phaser.Scene
{
constructor ()
{
super({ key: "subgame" });
}
create ()
{
this.bg = this.add.tileSprite(0, 0, 800, 600, 'bg').setOrigin(0);
this.add.image(400, 300, 'space', this.registry.get('planet')).setScale(0.5);
this.add.text(10, 10, 'Click to return', { font: '16px Courier', fill: '#00ff00' });
// Click to quit this sub-"game"
this.input.once('pointerdown', () => {
// We're done here, so stop this Scene and wake the world up
this.scene.stop();
this.scene.wake('world');
});
}
}
Структура класса SubGame
Любая сцена в Phaser — это класс, расширяющий Phaser.Scene. Ключевой момент — присвоение сцене уникального ключа, по которому мы будем к ней обращаться.
class SubGame extends Phaser.Scene
{
constructor ()
{
super({ key: "subgame" });
}
// ... остальной код
}
В конструкторе мы вызываем super(), передавая объект конфигурации. Поле key: "subgame" задает системное имя нашей сцены. Именно этот ключ мы будем использовать для ее запуска (this.scene.start('subgame')) или остановки.
Создание игровых объектов в методе create
Метод create() автоматически вызывается фреймворком, когда сцена переходит в активное состояние. Здесь мы инициализируем все визуальные элементы и логику.
Давайте разберем код построчно. Сначала создается фоновый тайл-спрайт, который можно будет прокручивать, если это потребуется.
this.bg = this.add.tileSprite(0, 0, 800, 600, 'bg').setOrigin(0);
Затем мы добавляем изображение планеты. Ключевой момент — мы не хардкодим текстуру, а получаем ее ключ из общего реестра данных игры.
this.add.image(400, 300, 'space', this.registry.get('planet')).setScale(0.5);
this.registry.get('planet') извлекает значение, которое могла сохранить основная сцена перед запуском SubGame. Это простой и эффективный способ передачи данных между сценами.
Наконец, добавляем текстовую подсказку для игрока.
this.add.text(10, 10, 'Click to return', { font: '16px Courier', fill: '#00ff00' });
Обработка ввода и возврат в основную сцену
Вся логика выхода из под-игры умещается в обработчик одного клика. Мы используем this.input.once, чтобы событие сработало только один раз, что предотвращает случайные повторные вызовы.
this.input.once('pointerdown', () => {
this.scene.stop();
this.scene.wake('world');
});
Внутри коллбэка происходят два важных действия:
1. `this.scene.stop()` — полностью останавливает текущую сцену (`subgame`). Ее методы `update` и `render` перестают вызываться, а все созданные в ней объекты уничтожаются.
2. `this.scene.wake('world')` — "пробуждает" сцену с ключом `world`. Предполагается, что это наша основная игровая сцена, которая была предварительно переведена в спящий режим (`this.scene.sleep('world')`) при запуске `subgame`. Пробуждение восстанавливает ее работу без перезагрузки, сохраняя все состояние игры.
Именно такая связка stop() для текущей сцены и wake() для предыдущей обеспечивает плавный и контролируемый переход.
Как запустить SubGame из основной сцены
Чтобы наш пример работал, основная сцена (например, World) должна корректно запустить SubGame. Вот типичная последовательность действий.
Сначала, вероятно, в ответ на какое-то событие (клик по объекту, сбор предмета), основная сцена "засыпает" и запускает под-игру.
// В основном классе сцены World
openSubGame() {
// 1. Переводим основную сцену в спящий режим
this.scene.sleep();
// 2. Запускаем сцену под-игры
this.scene.launch('subgame');
}
Перед этим, для передачи данных, можно использовать реестр (registry).
// Где-то в коде основной сцены, перед launch
this.registry.set('planet', 'planetEarth'); // Сохраняем ключ текстуры
Реестр — глобальное хранилище, доступное из любой сцены игры, что делает его удобным для простого обмена данными.
Что попробовать дальше
Вложенные сцены — это архитектурный паттерн в Phaser, который помогает поддерживать код в чистоте и порядке. Выделяя мини-игры, меню или кат-сцены в отдельные сцены, вы изолируете их логику, что упрощает отладку и дальнейшее расширение.
**Идеи для экспериментов:**
1. Передавайте через реестр не просто ключ текстуры, а целый объект с конфигурацией под-игры (сложность, тип врагов).
2. Вместо мгновенного возврата по клику добавьте в SubGame простую игровую механику (собрать N предметов) и возвращайтесь только по ее завершению.
3. Попробуйте не останавливать (stop) под-игру, а переводить ее в сон (sleep). Это позволит сохранить состояние, если игроку нужно будет вернуться в ту же мини-игру позже.
