О чем этот пример
Динамическое управление камерой — ключ к созданию захватывающих игровых миров. Плавные переходы между локациями и изменение масштаба не только улучшают визуальное восприятие, но и направляют внимание игрока. В этой статье мы разберем, как использовать методы `zoomTo` и `pan` для создания кинематографичных перемещений камеры по большой карте, с анимацией и различными эффектами плавности (easing).
Версия 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('map', 'assets/tests/camera/earthbound-scarab.png');
}
create ()
{
this.cameras.main.setBounds(0, 0, 1024, 2048);
this.add.image(0, 0, 'map').setOrigin(0);
this.cameras.main.setZoom(1);
this.cameras.main.centerOn(0, 0);
this.text = this.add.text(304, 230).setText('Click to move').setScrollFactor(0);
this.text.setShadow(1, 1, '#000000', 2);
let pos = 0;
this.input.on('pointerdown', function () {
const cam = this.cameras.main;
if (pos === 0)
{
cam.pan(767, 1096, 2000, 'Power2');
cam.zoomTo(4, 3000);
pos++;
}
else if (pos === 1)
{
cam.pan(703, 1621, 2000, 'Elastic');
cam.zoomTo(2, 3000);
pos++;
}
else if (pos === 2)
{
cam.pan(256, 623, 2000, 'Sine.easeInOut');
cam.zoomTo(1, 3000);
pos++;
}
else if (pos === 3)
{
cam.pan(166, 304, 2000);
cam.zoomTo(4, 1500);
pos++;
}
else if (pos === 4)
{
cam.pan(624, 158, 2000);
cam.zoomTo(0.5, 3000);
pos++;
}
else if (pos === 5)
{
cam.pan(680, 330, 2000);
pos++;
}
else if (pos === 6)
{
cam.pan(748, 488, 2000);
pos++;
}
else if (pos === 7)
{
cam.pan(1003, 1719, 2000);
pos = 0;
}
}, this);
}
update ()
{
const cam = this.cameras.main;
this.text.setText(['Click to move', 'x: ' + cam.scrollX, 'y: ' + cam.scrollY ]);
}
}
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
pixelArt: true,
physics: {
default: 'arcade',
},
scene: Example
};
const game = new Phaser.Game(config);
Подготовка сцены и загрузка карты
Первым делом в методе preload загружается изображение карты. Важно использовать setBaseURL, чтобы указать базовый путь к ресурсам.
В методе create происходит основная настройка. Камера получает границы (setBounds), соответствующие размеру карты, что ограничивает её перемещение. Изображение карты добавляется в начало координат (0,0) с помощью setOrigin(0). Исходный зум камеры устанавливается в 1 (100%), и она центрируется в начале координат.
this.cameras.main.setBounds(0, 0, 1024, 2048);
this.add.image(0, 0, 'map').setOrigin(0);
this.cameras.main.setZoom(1);
this.cameras.main.centerOn(0, 0);
Обработка кликов и логика переходов
В примере используется переменная pos в качестве счётчика для циклического перебора заранее заданных точек на карте. При каждом клике (pointerdown) выполняется цепочка условий if/else if, которая определяет, какую точку посетить следующей.
let pos = 0;
this.input.on('pointerdown', function () {
const cam = this.cameras.main;
if (pos === 0) {
// Первый переход
cam.pan(767, 1096, 2000, 'Power2');
cam.zoomTo(4, 3000);
pos++;
}
// ... остальные условия
}, this);
Каждый переход состоит из двух операций: панорамирования (pan) и изменения зума (zoomTo). Оба метода могут принимать время анимации в миллисекундах и строку с названием функции плавности (easing).
Методы pan и zoomTo в деталях
Метод cam.pan(x, y, duration, ease, force, callback) плавно перемещает камеру к указанным координатам scrollX и scrollY.
Метод cam.zoomTo(zoom, duration) плавно изменяет масштаб камеры до заданного значения. Зум, равный 1, соответствует исходному размеру, 2 — увеличению в два раза, 0.5 — уменьшению вдвое.
// Переместить камеру к координатам (767, 1096) за 2 секунды с плавностью 'Power2'
cam.pan(767, 1096, 2000, 'Power2');
// Увеличить масштаб камеры до 4x за 3 секунды
cam.zoomTo(4, 3000);
Функции плавности (например, 'Elastic', 'Sine.easeInOut') контролируют ускорение анимации, делая перемещения более естественными. Если ease не указан, используется линейная интерполяция.
Отображение позиции камеры в реальном времени
Чтобы визуализировать текущее положение камеры, в методе update текст на экране обновляется каждый кадр. Свойства cam.scrollX и cam.scrollY возвращают текущие координаты камеры.
update ()
{
const cam = this.cameras.main;
this.text.setText(['Click to move', 'x: ' + cam.scrollX, 'y: ' + cam.scrollY ]);
}
Текст создаётся в create с параметром setScrollFactor(0), что делает его неподвижным относительно экрана, а не игрового мира.
Конфигурация игры и важные настройки
Ключевая настройка для корректного отображения пиксельной графики — pixelArt: true. Она отключает сглаживание текстур. Также в конфиге определяется основной класс сцены Example.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
pixelArt: true, // Важно для pixel-art игр
physics: {
default: 'arcade',
},
scene: Example // Наша сцена
};
const game = new Phaser.Game(config);
Что попробовать дальше
Методы pan и zoomTo — мощный инструмент для создания навигации по большим игровым мирам, кат-сцен или динамических эффектов. Для экспериментов попробуйте
- Связать перемещение камеры с движением игрока, плавно следуя за ним с небольшим отставанием
- Создать систему кат-сцен, запрограммировав последовательность
panиzoomToпо таймеру - Использовать разные функции плавности из пакета Phaser (например, 'Bounce', 'Back') для придания анимациям уникального характера
