О чем этот пример
Визуальное представление игрового мира часто превышает размеры экрана. Камеры в Phaser 3 позволяют контролировать, какую часть мира видит игрок, создавая эффекты прокрутки, разделения экрана или динамического слежения. Этот пример демонстрирует мощную и гибкую систему камер, показывая, как несколько независимых видов могут работать в одном сцене, открывая возможности для создания мини-карт, режимов разделенного экрана или сложных визуальных эффектов.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
var iter = 0;
var horizontalCamera;
var verticalCamera;
var circularCamera;
class Example extends Phaser.Scene
{
constructor ()
{
super();
}
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('CherilPerils', 'assets/tests/camera/CherilPerils.png');
this.load.image('clown', 'assets/sprites/clown.png');
}
create ()
{
this.image = this.add.image(0, 0, 'CherilPerils').setOrigin(0);
this.cameras.main.setSize(400, 300);
horizontalCamera = this.cameras.add(400, 0, 400, 300);
verticalCamera = this.cameras.add(0, 300, 400, 300);
circularCamera = this.cameras.add(400, 300, 400, 300);
for (var i = 0; i < 1000; i++)
{
this.add.image(Math.random() * 1000, Math.random() * 1240, 'clown');
}
}
update ()
{
var halfWidth = this.image.texture.source[0].width / 2;
var quarterWidth = halfWidth / 2;
var halfHeight = this.image.texture.source[0].height / 2;
var quarterHeight = halfHeight / 2;
horizontalCamera.scrollX = (halfWidth - quarterWidth + (Math.cos(iter) * quarterWidth))|0;
verticalCamera.scrollY = (halfHeight - quarterHeight + (Math.sin(iter) * quarterHeight))|0;
circularCamera.scrollX = (halfWidth - quarterWidth + (Math.cos(iter) * quarterWidth))|0;
circularCamera.scrollY = (halfHeight - quarterHeight + (Math.sin(iter) * quarterHeight))|0;
iter += 0.02;
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example,
width: 800,
height: 600
};
const game = new Phaser.Game(config);
Инициализация сцены и загрузка ресурсов
Класс Example расширяет базовый Phaser.Scene. В методе constructor() вызывается родительский конструктор.
В методе preload() задается базовый URL для загрузки и загружаются два изображения: большое фоновое изображение 'CherilPerils' и спрайт 'clown', который будет использоваться множество раз.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('CherilPerils', 'assets/tests/camera/CherilPerils.png');
this.load.image('clown', 'assets/sprites/clown.png');
}
Создание мира и настройка камер
В методе create() сначала добавляется фоновое изображение в точку (0, 0) с установленным в ноль origin, чтобы его левый верхний угол совпал с началом координат мира.
Затем основной камере this.cameras.main задается размер 400x300 пикселей. По умолчанию она расположена в (0, 0), поэтому теперь она показывает только левый верхний угол большого изображения.
Далее создаются три дополнительные камеры с помощью метода this.cameras.add(). Каждая получает свои координаты и размеры, формируя сетку 2x2 на canvas размером 800x600.
create ()
{
this.image = this.add.image(0, 0, 'CherilPerils').setOrigin(0);
this.cameras.main.setSize(400, 300);
horizontalCamera = this.cameras.add(400, 0, 400, 300);
verticalCamera = this.cameras.add(0, 300, 400, 300);
circularCamera = this.cameras.add(400, 300, 400, 300);
}
После настройки камер в мир добавляется 1000 случайно размещенных спрайтов клоуна. Все камеры будут отображать один и тот же мир, но с разной позицией прокрутки.
for (var i = 0; i < 1000; i++)
{
this.add.image(Math.random() * 1000, Math.random() * 1240, 'clown');
}
Динамическое управление прокруткой камер
Сердце примера — метод update(), который вызывается каждый кадр. Здесь вычисляются новые значения прокрутки для трех дополнительных камер.
Сначала определяются ключевые точки изображения-фона: половина и четверть его ширины и высоты. Эти значения используются для ограничения области прокрутки.
var halfWidth = this.image.texture.source[0].width / 2;
var quarterWidth = halfWidth / 2;
var halfHeight = this.image.texture.source[0].height / 2;
var quarterHeight = halfHeight / 2;
Глобальная переменная iter плавно увеличивается каждое обновление, обеспечивая непрерывную анимацию.
Прокрутка камер задается через свойства scrollX и scrollY. Формула (half - quarter + (тригонометрическая_функция(iter) * quarter))|0 обеспечивает движение в пределах центральной половины изображения. Оператор |0 используется для быстрого преобразования результата в целое число.
* horizontalCamera: движется только по горизонтали (scrollX) по косинусоидальной траектории.
* verticalCamera: движется только по вертикали (scrollY) по синусоидальной траектории.
* circularCamera: движется и по горизонтали, и по вертикали, используя косинус и синус от одного аргумента, что создает круговое движение.
horizontalCamera.scrollX = (halfWidth - quarterWidth + (Math.cos(iter) * quarterWidth))|0;
verticalCamera.scrollY = (halfHeight - quarterHeight + (Math.sin(iter) * quarterHeight))|0;
circularCamera.scrollX = (halfWidth - quarterWidth + (Math.cos(iter) * quarterWidth))|0;
circularCamera.scrollY = (halfHeight - quarterHeight + (Math.sin(iter) * quarterHeight))|0;
iter += 0.02;
Основная камера (this.cameras.main) остается статичной, показывая фиксированный участок мира.
Сборка и запуск игры
Конфигурационный объект config определяет основные параметры игры: тип рендерера, родительский DOM-элемент, главную сцену, а также размеры canvas (800x600), которые идеально соответствуют расположению четырех камер по 400x300 каждая.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
scene: Example,
width: 800,
height: 600
};
const game = new Phaser.Game(config);
Что попробовать дальше
Этот пример наглядно демонстрирует, что камеры в Phaser — это не просто средство следования за игроком, а самостоятельные объекты для управления областью видимости. Вы можете создавать несколько видов, независимо управлять их позицией, масштабом, вращением и даже эффектами. Для экспериментов попробуйте: изменить формулу движения на более сложную (например, по эллипсу или Lissajous curve), добавить zoom или rotation камерам в update(), реализовать плавное слежение одной из камер за случайно выбранным клоуном или добавить обработку ввода для ручного управления прокруткой.
