О чем этот пример
В Phaser 3 сцены управляются в виде списка, и их порядок напрямую влияет на рендеринг и обработку ввода. Метод `moveUp()` позволяет динамически менять позицию активной сцены в этом списке. Эта техника полезна для создания сложных UI-переходов, модальных окон, пауз или систем приоритетов, когда одной сцене нужно временно оказаться поверх других без её полной остановки.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class DemoA extends Phaser.Scene
{
constructor ()
{
super({ key: 'demoA', active: true });
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('picA', 'assets/pics/lance-overdose-loader-eye.png');
}
create ()
{
this.add.image(400, 300, 'picA');
this.input.on('pointerup', function ()
{
this.scene.moveUp();
}, this);
}
}
class DemoB extends Phaser.Scene
{
constructor ()
{
super({ key: 'demoB', active: true });
}
preload ()
{
// this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('picB', 'assets/pics/sukasuka-chtholly.png');
}
create ()
{
this.add.image(400, 500, 'picB');
}
}
class DemoC extends Phaser.Scene
{
constructor ()
{
super({ key: 'demoC', active: true });
}
preload ()
{
// this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('picC', 'assets/pics/titan-mech.png');
}
create ()
{
this.add.image(300, 300, 'picC');
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
parent: 'phaser-example',
scene: [ DemoA, DemoB, DemoC ]
};
const game = new Phaser.Game(config);
Понимание порядка сцен
Когда вы передаёте массив классов сцен в конфигурацию игры, Phaser создаёт их экземпляры и помещает в управляемый список. Порядок в этом списке определяет две ключевые вещи:
1. **Отрисовка (рендеринг):** Сцены рендерятся последовательно, от начала списка к концу. Таким образом, сцена, находящаяся позже в списке, будет отрисована поверх предыдущих. 2. **Обработка ввода:** По умолчанию, если несколько сцен обрабатывают один и тот же тип ввода (например, клик), событие будет передано им всем, начиная с верхней (последней в списке) сцены.
Изначальный порядок в нашем примере задаётся массивом [ DemoA, DemoB, DemoC ]. Это значит, что сначала отрисуется DemoA, затем поверх неё DemoB, и, наконец, сверху всего DemoC.
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
parent: 'phaser-example',
scene: [ DemoA, DemoB, DemoC ] // Исходный порядок сцен
};
Как работает scene.moveUp()
Метод moveUp() принадлежит объекту SceneManager и вызывается для текущей (активной) сцены через this.scene. Его задача — переместить текущую сцену на одну позицию выше в внутреннем списке управления сценами.
В контексте нашего примера, когда вы кликаете (событие pointerup) в сцене DemoA, происходит следующее:
1. Исходный порядок: [DemoA, DemoB, DemoC].
2. Вызывается this.scene.moveUp() для DemoA.
3. DemoA меняется местами со следующей за ней сценой в списке, то есть с DemoB.
4. Новый порядок становится: [DemoB, DemoA, DemoC].
Код, который это реализует, находится в методе create сцены DemoA:
create ()
{
this.add.image(400, 300, 'picA');
this.input.on('pointerup', function ()
{
this.scene.moveUp(); // Перемещает DemoA вверх по списку
}, this);
}
Важно отметить, что moveUp() работает с **активной** сценой, из которой он вызван. Нельзя извне переместить неактивную сцену, не сделав её активной предварительно.
Визуальный результат и практическое применение
После вызова moveUp() сцена DemoA (с изображением глаза) моментально окажется поверх сцены DemoB (с аниме-девушкой), но всё ещё под сценой DemoC (с мехом). Визуально это выглядит как мгновенная смена слоёв.
Почему это полезно на практике?
* **Динамические HUD/UI:** Вы можете держать UI-сцену внизу списка и поднимать её наверх только когда нужно показать сообщение или меню. * **Система паузы:** Сцена с меню паузы может быть добавлена в конец списка, а по нажатию кнопки "Продолжить" — опущена вниз, чтобы игровая сцена снова оказалась наверху для обработки ввода. * **Управление фокусом:** В играх с несколькими игровыми областями (например, карта и диалоги) вы можете переключать фокус, меняя порядок сцен, вместо их остановки и перезапуска.
Обратите внимание, что в примере сцены DemoB и DemoC не содержат кода для обработки ввода. Они просто отрисовывают изображения. Вся логика перемещения заключена в DemoA.
Семейство методов для управления порядком
moveUp() — не единственный метод для управления позицией сцены. SceneManager предоставляет целый набор методов:
* moveDown(): Перемещает сцену на одну позицию вниз по списку.
* moveAbove(key): Перемещает сцену **над** сценой с указанным ключом.
* moveBelow(key): Перемещает сцену **под** сцену с указанным ключом.
* sendToBack(): Перемещает сцену в самый низ списка (первой для отрисовки).
* bringToTop(): Перемещает сцену на самый верх списка (последней для отрисовки).
Например, чтобы мгновенно переместить текущую сцену поверх всех остальных, можно использовать bringToTop():
this.input.on('pointerup', function ()
{
this.scene.bringToTop(); // DemoA окажется поверх DemoC
}, this);
Эти методы дают полный контроль над стеком рендеринга сцен в реальном времени.
Что попробовать дальше
Метод moveUp() и его аналоги — это мощный, но часто упускаемый из виду инструмент для управления визуальным стеком и логикой приложения в Phaser 3. Они позволяют создавать динамические интерфейсы без необходимости скрывать/показывать объекты вручную или управлять их глубиной (depth) в рамках одной сцены.
**Идеи для экспериментов:**
1. Создайте сцену-оверлей с полупрозрачным чёрным фоном и текстом "ПАУЗА". Реализуйте систему, где нажатие ESC поднимает эту сцену наверх, а повторное нажатие — опускает вниз.
2. Реализуйте систему уведомлений: при событии в игре (подбор предмета) поднимайте небольшую UI-сцену с сообщением наверх, а через 2 секунды автоматически возвращайте её вниз.
3. Создайте несколько интерактивных сцен (с обработкой кликов) и поэкспериментируйте с moveUp()/moveDown(), чтобы увидеть, как меняется приоритет получения событий ввода.
