О чем этот пример
В игровых проектах часто возникает необходимость разделить интерфейс и игровой мир. Например, чтобы элементы HUD оставались статичными, пока фон вращается или масштабируется. Phaser 3 предлагает для этого элегантное решение через систему камер и метод `ignore`. В этой статье мы разберем, как создать отдельную камеру для UI, исключить из рендеринга ненужные объекты и добиться независимого поведения слоев.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
var UIText2;
class Example extends Phaser.Scene
{
constructor ()
{
super();
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('einstein', 'assets/pics/ra-einstein.png');
}
create ()
{
const image = this.add.image(400, 300, 'einstein');
this.UIText1 = this.add.text(0, 32, '0');
this.UIText2 = this.add.text(0, 64, '0');
this.cont = this.add.container();
this.cont.add([this.UIText1, this.UIText2]);
// Add in a new camera, the same size and position as the main camera
this.UICam = this.cameras.add(0, 0, 800, 600);
// The main camera will not render the container
this.cameras.main.ignore(this.cont);
// The new UI Camera will not render the background image
this.UICam.ignore(image);
}
update ()
{
this.UIText1.setText("Main camera rotation: " + this.cameras.main.rotation);
this.UIText2.setText("Main camera zoom: " + this.cameras.main.zoom);
//wobble the container
this.cont.y = Math.sin(this.time.now / 100) * 10;
this.cameras.main.setZoom(Math.abs(Math.sin(this.cameras.main.rotation)) * 0.5 + 1);
this.cameras.main.rotation += 0.01;
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Зачем нужно несколько камер?
Основная камера в Phaser (this.cameras.main) управляет тем, какую часть игрового мира видит игрок. Но что, если нужно поверх игрового мира отображать элементы интерфейса (здоровье, счет, меню), которые не должны вращаться или масштабироваться вместе с миром?
Решение — создать вторую камеру, которая будет рендерить только UI. Каждая камера в Phaser — это независимый вид на сцену. Объекты можно настраивать так, чтобы они отображались только в определенных камерах. Это и есть разделение на слои.
Настройка сцены и создание объектов
В примере сначала создается фоновая картинка и два текстовых поля. Текст должен стать частью пользовательского интерфейса.
const image = this.add.image(400, 300, 'einstein');
this.UIText1 = this.add.text(0, 32, '0');
this.UIText2 = this.add.text(0, 64, '0');
Затем текстовые элементы помещаются в контейнер. Контейнер (Phaser.GameObjects.Container) — это удобный способ группировки нескольких игровых объектов для совместного управления.
this.cont = this.add.container();
this.cont.add([this.UIText1, this.UIText2]);
Создание UI-камеры и настройка игнорирования
Ключевой момент — создание второй камеры. Она имеет те же размеры и положение, что и основная (полноэкранная).
this.UICam = this.cameras.add(0, 0, 800, 600);
Теперь нужно "научить" камеры игнорировать определенные объекты. Метод ignore объекта камеры исключает переданные игровые объекты из списка рендеринга для этой камеры.
// Основная камера не будет рендерить контейнер с текстом
this.cameras.main.ignore(this.cont);
// Новая UI-камера не будет рендерить фоновое изображение
this.UICam.ignore(image);
В результате фон (image) рендерится только в основной камере, а контейнер с текстом (this.cont) — только в UI-камере. Они стали независимыми слоями.
Анимация и независимое обновление слоев
В методе update происходит анимация, которая наглядно демонстрирует независимость слоев.
Значения вращения и зума основной камеры выводятся в текстовых полях. Сами поля (через контейнер) совершают колебательное движение по оси Y.
this.cont.y = Math.sin(this.time.now / 100) * 10;
Основная камера динамически меняет свой зум на основе текущего угла вращения.
this.cameras.main.setZoom(Math.abs(Math.sin(this.cameras.main.rotation)) * 0.5 + 1);
this.cameras.main.rotation += 0.01;
Главное наблюдение: текст, привязанный к UI-камере, колеблется вверх-вниз, но НЕ вращается и НЕ масштабируется вместе с безумным зумом и вращением основной камеры, которая влияет только на фон. Это и есть цель достигнута.
Что попробовать дальше
Использование нескольких камер с методом ignore — мощный паттерн в Phaser 3 для создания сложных многослойных сцен. Он идеально подходит для HUD, меню, эффектов постобработки или разделения кооперативных экранов.
**Идеи для экспериментов:**
1. Добавьте больше UI-элементов (иконки, полоски здоровья) в контейнер и анимируйте их.
2. Создайте третью камеру специально для эффектов частиц и настройте игнорирование для других слоев.
3. Попробуйте перемещать UI-камеру независимо от основной, создавая эффект "дрожания" интерфейса при ударах.
