О чем этот пример
В Phaser управление отображением часто сводится к одной сцене и одной основной камере. Но что, если вам нужно создать сложный интерфейс, разделить экран на несколько независимых областей или реализовать эффект "картинка в картинке"? Пример с множеством сцен и камер демонстрирует мощный подход к решению таких задач. Вы научитесь запускать несколько активных сцен одновременно, управлять их видимостью с помощью камер и создавать динамичные, многослойные игровые миры, что особенно полезно для сложных HUD, мини-карт или многопользовательских экранов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Background extends Phaser.Scene
{
constructor ()
{
super({ key: 'background', active: true });
this.image;
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('einstein', 'assets/pics/ra-einstein.png');
}
create ()
{
this.image = this.add.image(200, 150, 'einstein');
this.cameras.main.setSize(400, 300);
this.cameras.add(400, 0, 400, 300);
this.cameras.add(0, 300, 400, 300);
this.cameras.add(400, 300, 400, 300);
}
update ()
{
this.image.rotation += 0.01;
}
}
class Demo extends Phaser.Scene
{
constructor ()
{
super({ key: 'demo', active: true });
}
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.image(400, 300, 'arrow').setOrigin(0, 0.5);
}
update (time, delta)
{
this.arrow.rotation += 0.01;
}
}
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: [ Background, Demo ]
};
const game = new Phaser.Game(config);
Архитектура примера: две сцены и четыре камеры
Ключевая особенность этого примера — одновременная работа двух сцен ('background' и 'demo'). Обе сцены создаются как активные (active: true в конструкторе), что означает их одновременное обновление и отрисовку. Однако они отображаются не на весь экран игры, а только в тех областях, которые контролируют их камеры.
Игра имеет разрешение 800x600 пикселей. Сцена Background делит это пространство на четыре квадранта размером 400x300 с помощью четырех камер. Сцена Demo использует одну, но тоже нестандартную камеру. Это позволяет создать композитное изображение из нескольких источников.
Сцена Background: разбивка экрана на камеры
Сцена Background загружает изображение и создает из него вращающийся спрайт. Основная магия происходит в методе create().
Сначала основная камера сцены (this.cameras.main) уменьшается до размера левого верхнего квадранта.
this.cameras.main.setSize(400, 300);
Затем создаются три дополнительные камеры для оставшихся трех квадрантов. Метод this.cameras.add() принимает координаты X, Y, ширину и высоту области просмотра (viewport).
this.cameras.add(400, 0, 400, 300); // Правый верхний квадрант
this.cameras.add(0, 300, 400, 300); // Левый нижний квадрант
this.cameras.add(400, 300, 400, 300); // Правый нижний квадрант
Важно: все четыре камеры (основная и три добавленные) принадлежат одной сцене Background и отображают один и тот же контент — вращающееся изображение Эйнштейна. Каждая камера — это просто "окно" в мир этой сцены, расположенное в своей позиции на общем холсте игры.
В update() объект изображения постоянно вращается, и это вращение видно во всех четырех "окнах"-камерах одновременно.
Сцена Demo: камера на пол-экрана
Вторая сцена, Demo, работает параллельно. Она загружает спрайт стрелки и также заставляет его вращаться.
Её основная камера НЕ была изменена с помощью setSize(). По умолчанию камера занимает весь экран игры (800x600). Однако, поскольку сцена Background уже отрисовала свой контент во всех четырех квадрантах, возникает вопрос: куда же отрисуется сцена Demo?
Ответ заключается в порядке объявления сцен в конфигурации игры. Сцена Background указана первой в массиве scene: [ Background, Demo ]. В Phaser порядок отрисовки сцен по умолчанию соответствует порядку в этом массиве. Это значит, что сначала отрисовывается Background (во все четыре квадранта), а затем поверх неё отрисовывается Demo.
Но камера сцены Demo по-прежнему покрывает весь экран. Чтобы увидеть содержимое Background под ней, камере Demo нужно задать меньший размер и другую позицию. В исходном коде примера этого не сделано, поэтому сцена Demo полностью перекрывает Background. Чтобы реализовать задуманный в примере эффект (стрелка в центре поверх фона), нужно настроить камеру сцены Demo аналогично первой камере Background.
// В методе create() сцены Demo:
this.cameras.main.setViewport(200, 150, 400, 300);
Метод setViewport() делает то же самое, что setSize() для основной камеры, но также позволяет задать позицию (X, Y). Это разместило бы камеру Demo поверх левого верхнего квадранта, отрисованного Background.
Конфигурация игры и порядок сцен
Объявление игры — стандартный пункт. Ключевой параметр здесь — массив scene.
const config = {
type: Phaser.WEBGL,
width: 800,
height: 600,
backgroundColor: '#000000',
parent: 'phaser-example',
scene: [ Background, Demo ] // Порядок имеет значение!
};
Установка active: true в конструкторах обеих сцен гарантирует, что их методы preload(), create() и update() будут вызваны. Без этого флага сцены нужно было бы запускать вручную через this.scene.start().
Черный фон (backgroundColor) будет виден только в тех пикселях холста, которые не перекрыты viewport'ами ни одной из активных камер.
Что попробовать дальше
Этот пример открывает путь к созданию сложных визуальных композиций в Phaser. Используя несколько активных сцен и управляя их камерами, вы можете эффективно разделять логику и графику разных частей игры (например, фон, игровой мир, интерфейс, мини-карта). Для экспериментов попробуйте
- Добавить интерактивность — сделайте так, чтобы клик в одном из квадрантов влиял только на контент в нём, используя
camera.setInteractive() - Создайте эффект "дробления" экрана, анимируя позицию и размер камер с помощью трещовок (tweens)
- Реализуйте локальный мультиплеер на одном экране, где у каждого игрока своя камера, следящая за его героем в общем мире
