О чем этот пример
Любая игра — это набор состояний: меню, игровой уровень, экран результатов. В Phaser 3 за управление этими состояниями отвечает система сцен (Scenes). Прямое переключение между сценами — фундаментальный механизм, на котором строится вся логика навигации в вашем проекте. Эта статья разберет простой пример, показывающий, как объявить несколько сцен и переключаться между ними по клику мыши. Вы научитесь правильно инициализировать сцены, запускать их и понимать жизненный цикл, что станет основой для создания сложных многоэкранных игр.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class SceneA extends Phaser.Scene {
constructor ()
{
super({ key: 'sceneA' });
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('face', 'assets/pics/bw-face.png');
}
create ()
{
this.face = this.add.image(400, 300, 'face');
this.input.manager.enabled = true;
this.input.once('pointerdown', function () {
this.scene.start('sceneB');
}, this);
}
}
class SceneB extends Phaser.Scene {
constructor ()
{
super({ key: 'sceneB' });
}
preload ()
{
// this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('arrow', 'assets/sprites/longarrow.png');
}
create ()
{
this.arrow = this.add.sprite(400, 300, 'arrow').setOrigin(0, 0.5);
this.input.once('pointerdown', function (event) {
this.scene.start('sceneC');
}, this);
}
update ()
{
this.arrow.rotation += 0.01;
}
}
class SceneC extends Phaser.Scene {
constructor ()
{
super({ key: 'sceneC' });
}
preload ()
{
// this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('mech', 'assets/pics/titan-mech.png');
}
create ()
{
this.add.sprite(Phaser.Math.Between(300, 600), 300, 'mech');
this.input.once('pointerdown', function (event) {
this.scene.start('sceneA');
}, this);
}
}
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: [ SceneA, SceneB, SceneC ]
};
var game = new Phaser.Game(config);
Структура и конфигурация сцены
Каждая сцена в Phaser — это класс, расширяющий Phaser.Scene. В конструкторе мы задаем уникальный ключ сцены, по которому будем к ней обращаться. Этот ключ передается в объект конфигурации, который получает метод super().
Все сцены, которые вы хотите использовать в игре, передаются массивом в главную конфигурацию игры в поле scene. Порядок в массиве может влиять на порядок инициализации, но на переключение не влияет.
class SceneA extends Phaser.Scene {
constructor ()
{
super({ key: 'sceneA' });
}
}
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
parent: 'phaser-example',
scene: [ SceneA, SceneB, SceneC ]
};
var game = new Phaser.Game(config);
Жизненный цикл: загрузка и создание объектов
У сцены есть предопределенные методы, которые Phaser вызывает автоматически. Два основных — preload() и create().
Метод preload() служит для загрузки всех необходимых ресурсов (изображений, звуков, данных) перед созданием сцены. В примере для загрузки используется метод this.load.image(). Важно отметить, что setBaseURL() вызывается только в первой сцене (SceneA), а в последующих закомментировано, чтобы не переопределять базовый путь.
Метод create() вызывается один раз, когда ресурсы загружены. Здесь происходит создание игровых объектов, спрайтов, настройка физики и ввода. Например, в SceneA создается изображение, а в SceneB — спрайт со смещенной точкой вращения (setOrigin(0, 0.5)).
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('face', 'assets/pics/bw-face.png');
}
create ()
{
this.face = this.add.image(400, 300, 'face');
}
Механизм переключения: метод start
Переключение между сценами осуществляется с помощью менеджера сцен, доступного как this.scene. Ключевой метод для перехода — start(). Он останавливает текущую сцену (вызывая ее методы shutdown и sleep) и запускает целевую сцену (вызывая ее init, preload, create и т.д.).
В примере переход инициируется по однократному клику мыши. Обработчик события вешается с помощью this.input.once(), что гарантирует его однократное срабатывание.
this.input.once('pointerdown', function () {
this.scene.start('sceneB');
}, this);
Обратите внимание на третий аргумент this в once(). Он задает контекст, в котором будет выполнена функция-обработчик. Без этого this.scene внутри функции был бы undefined.
Разные состояния сцен: статика и анимация
Пример демонстрирует, что сцены могут находиться в разных состояниях. SceneA и SceneC — статичны. После создания объектов они просто ждут клика для перехода.
SceneB, в отличие от них, активна. Она содержит метод update(), который Phaser вызывает на каждом кадре игры. Внутри него происходит вращение спрайта стрелки. Это показывает, что игровая логика и анимации продолжают работать, пока активна текущая сцена.
update ()
{
this.arrow.rotation += 0.01;
}
Когда вы вызываете this.scene.start('sceneC') из SceneB, ее цикл update() прекращает выполняться, и управление передается SceneC.
Что попробовать дальше
Прямое переключение сцен через start() — это базовый, но мощный инструмент организации кода. Он позволяет четко разделить логику разных частей игры. Для экспериментов попробуйте
- Передавать данные между сценами через аргументы метода
start('key', data) - Использовать
this.scene.launch()для одновременной работы нескольких сцен (например, HUD поверх уровня) - Управлять переходами не по клику, а по таймеру или выполнению игрового условия
