О чем этот пример
Один из базовых паттернов в Phaser 3 — запуск одной сцены из другой. В этой статье мы разберем пример, где игра начинает со сцены A, которая мгновенно запускает сцену B, та — сцену C, и так далее. Этот подход полезен для организации загрузки ресурсов, показа интро-экранов или управления сложным состоянием игры, где каждый этап выделен в отдельную сцену. Вы научитесь управлять жизненным циклом сцен, не дожидаясь их полной инициализации.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class SceneA extends Phaser.Scene {
constructor ()
{
super('sceneA');
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('face', 'assets/pics/bw-face.png');
this.load.image('arrow', 'assets/sprites/longarrow.png');
}
create ()
{
this.scene.start('sceneB');
}
}
class SceneB extends Phaser.Scene {
constructor ()
{
super('sceneB');
}
create ()
{
this.scene.start('sceneC');
}
}
class SceneC extends Phaser.Scene {
constructor ()
{
super('sceneC');
}
create ()
{
this.scene.start('sceneD');
}
}
class SceneD extends Phaser.Scene {
constructor ()
{
super('sceneD');
}
create ()
{
this.face = this.add.image(400, 300, 'face');
this.arrow = this.add.sprite(400, 300, 'arrow').setOrigin(0, 0.5);
}
update ()
{
this.arrow.rotation += 0.01;
}
}
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
scene: [ SceneA, SceneB, SceneC, SceneD ]
};
var game = new Phaser.Game(config);
Стартовая сцена и ее роль
В Phaser 3 конфигурация игры определяет массив сцен, которые будут созданы. Первая сцена в массиве запускается автоматически.
Однако в нашем примере первая сцена (SceneA) не отображает ничего на экране. Ее задача — предзагрузить ресурсы для более поздних сцен и немедленно передать управление следующей сцене в цепочке. Это эффективный способ разделить логику загрузки от логики отображения. Сцена A выступает в роли "загрузочного экрана".
class SceneA extends Phaser.Scene {
constructor ()
{
super('sceneA');
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('face', 'assets/pics/bw-face.png');
this.load.image('arrow', 'assets/sprites/longarrow.png');
}
create ()
{
this.scene.start('sceneB');
}
}
Механизм переключения сцен
Ключевой метод для смены сцены — this.scene.start(). При его вызове текущая сцена останавливается, а указанная сцена запускается. Если целевая сцена еще не была запущена, Phaser создаст ее экземпляр и вызовет ее методы init(), preload() (если есть) и create().
В примере SceneB и SceneC не имеют собственной логики, кроме как передать управление дальше. Они служат простыми "прокси" или переходными состояниями. Такой паттерн может быть полезен для создания последовательности немедленных событий или тестирования порядка загрузки.
class SceneB extends Phaser.Scene {
constructor ()
{
super('sceneB');
}
create ()
{
this.scene.start('sceneC');
}
}
Финальная сцена с игровой логикой
Цепочка заканчивается на SceneD. Это первая и единственная сцена в примере, которая выполняет визуализацию и обновление состояния (update). Именно здесь отображаются предзагруженные в SceneA изображения и добавляется анимация.
Обратите внимание: хотя изображения были загружены в SceneA, они доступны во всех последующих сценах, так как менеджер загрузки (this.load) глобален для всей игры.
class SceneD extends Phaser.Scene {
constructor ()
{
super('sceneD');
}
create ()
{
this.face = this.add.image(400, 300, 'face');
this.arrow = this.add.sprite(400, 300, 'arrow').setOrigin(0, 0.5);
}
update ()
{
this.arrow.rotation += 0.01;
}
}
Конфигурация игры и порядок сцен
Массив scene в конфиге определяет порядок, в котором Phaser создает экземпляры сцен. Этот порядок важен для инициализации, но не диктует, какая сцена будет активна в данный момент. Активную сцену определяют вызовы this.scene.start().
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
scene: [ SceneA, SceneB, SceneC, SceneD ]
};
var game = new Phaser.Game(config);
После создания игры Phaser запускает первую сцену из массива (SceneA), и далее управление течет по цепочке, которую мы описали.
Что попробовать дальше
Пример демонстрирует фундаментальный принцип управления состоянием в Phaser 3 с помощью сцен. Вы можете использовать эту технику для создания многоэтапных загрузчиков, где каждая сцена отвечает за свой тип ресурсов, или для построения линейного повествования в игре. Для экспериментов попробуйте: добавить задержку между переключениями с помощью this.time.delayedCall; передавать данные между сценами через аргументы метода start(); или организовать возврат к предыдущей сцене с помощью this.scene.switch().
