О чем этот пример
Управление несколькими камерами — мощный инструмент для создания сложных интерфейсов, мини-карт или разделения экрана в мультиплеере. Часто возникает задача динамически изменять набор активных камер в ответ на действия игрока. В этой статье мы разберем практический пример, где камера удаляется при клике по ней и может быть создана заново в другом месте. Это полезно для редакторов уровней, систем наблюдения или кастомизируемых интерфейсов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
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/monika-krawinkel-amberstar-title.png');
}
create ()
{
this.image = this.add.image(100, 70, 'einstein');
// We're going to create 32 cameras in a 8x4 grid, making each 100x150 in size
this.cameras.main.setSize(100, 150);
this.cameras.main.name = 'Cam0';
let i = 1;
for (let y = 0; y < 4; y++)
{
for (let x = 0; x < 8; x++)
{
if (x === 0 && y === 0)
{
continue;
}
const tx = x * 100;
const ty = y * 150;
this.cameras.add(tx, ty, 100, 150, false, 'Cam' + i);
i++;
}
}
this.input.on(Phaser.Input.Events.POINTER_UP, function (pointer) {
const x = Phaser.Math.Snap.Floor(pointer.x, 100);
const y = Phaser.Math.Snap.Floor(pointer.y, 150);
const total = this.cameras.remove(pointer.camera);
if (total === 0)
{
const newCam = this.cameras.add(x, y, 100, 150);
console.log('Added Camera ID', newCam.id);
}
else
{
console.log('Removed Camera ID', pointer.camera.id);
}
}, this);
}
update ()
{
this.image.rotation += 0.01;
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
scene: Example
};
const game = new Phaser.Game(config);
Создание сетки камер
В примере создается 32 камеры, расположенные в сетке 8x4. Основная камера (this.cameras.main) уменьшается до размера 100x150 пикселей и задает шаблон для остальных.
this.cameras.main.setSize(100, 150);
this.cameras.main.name = 'Cam0';
Затем в двойном цикле создаются дополнительные камеры с помощью метода this.cameras.add(). Каждая камера имеет свои координаты (tx, ty), размер 100x150 и уникальное имя.
for (let y = 0; y < 4; y++) {
for (let x = 0; x < 8; x++) {
if (x === 0 && y === 0) continue;
const tx = x * 100;
const ty = y * 150;
this.cameras.add(tx, ty, 100, 150, false, 'Cam' + i);
i++;
}
}
Важно: первая ячейка сетки (x=0, y=0) пропускается, так как там уже находится основная камера. В результате мы получаем мозаику из камер, каждая из которых отображает одну и ту же вращающуюся картинку, но в своем прямоугольнике.
Обработка клика и удаление камеры
Логика динамического управления камерами привязана к событию клика (POINTER_UP). При клике определяется, по какой камере был произведен клик, и эта камера удаляется из системы.
this.input.on(Phaser.Input.Events.POINTER_UP, function (pointer) {
const total = this.cameras.remove(pointer.camera);
// ...
}, this);
Ключевой момент: объект pointer события содержит свойство pointer.camera — это ссылка на конкретную камеру, в области которой произошел клик. Метод this.cameras.remove() удаляет эту камеру из менеджера камер сцены и возвращает общее количество оставшихся камер. Если камер не осталось, в следующем разделе будет создана новая.
Создание новой камеры на месте клика
После удаления камеры проверяется, сколько их осталось. Если камер больше нет (total === 0), создается новая камера в координатах клика, приведенных к сетке.
const x = Phaser.Math.Snap.Floor(pointer.x, 100);
const y = Phaser.Math.Snap.Floor(pointer.y, 150);
if (total === 0) {
const newCam = this.cameras.add(x, y, 100, 150);
console.log('Added Camera ID', newCam.id);
}
Функции Phaser.Math.Snap.Floor() используются для привязки координат клика к шагу сетки (100 по X, 150 по Y). Это гарантирует, что новая камера встанет ровно в ячейку сетки, а не произвольно. Если камеры были удалены (т.е. total > 0), в консоль выводится ID удаленной камеры.
Вращение изображения как визуальный индикатор
Чтобы было наглядно видно, что все камеры отображают одну и ту же сцену, в методе update() происходит постоянное вращение изображения.
update () {
this.image.rotation += 0.01;
}
Это вращение синхронно отображается во всех активных камерах, что сразу показывает, какая область экрана сейчас "управляется" какой камерой. Если камеру удалить — в ее прямоугольнике изображение исчезнет. Если создать новую — в ее прямоугольнике снова начнется анимация.
Что попробовать дальше
Пример демонстрирует гибкость системы камер Phaser: их можно создавать, компоновать в сетку и удалять в реальном времени. Это открывает возможности для нестандартных интерфейсов. Для экспериментов попробуйте
- Удалять камеры не по клику, а по таймеру, создавая "мигающий" эффект
- Менять свойства камеры (например,
zoomилиalpha) перед удалением для анимации исчезновения - Сохранять массив удаленных камер и восстанавливать их в исходных позициях по нажатию клавиши
