О чем этот пример
Создание игр с большими уровнями, выходящими за пределы экрана, — классическая задача. Phaser предлагает мощные инструменты для управления камерой, которые позволяют плавно следить за игроком и масштабировать вид. В этой статье мы разберем пример, где камера следует за кораблем на тайловой карте, и объясним, как настроить ее поведение под свои нужды. Вы научитесь задавать границы мира, включать плавное преследование и управлять масштабом отображения.
Версия 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('ship', 'assets/sprites/fmship.png');
this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/super-mario.json');
this.load.image('tiles1', 'assets/tilemaps/tiles/super-mario.png');
}
create ()
{
this.cameras.main.setBounds(0, 0, 3392, 100);
this.physics.world.setBounds(0, 0, 3392, 240);
var map = this.make.tilemap({ key: 'map' });
var tileset = map.addTilesetImage('SuperMarioBros-World1-1', 'tiles1');
var layer = map.createLayer('World1', tileset, 0, 0);
this.cursors = this.input.keyboard.createCursorKeys();
// this.ship = this.physics.add.image(400, 100, 'ship').setAngle(90).setCollideWorldBounds(true);
this.ship = this.add.image(400, 100, 'ship').setAngle(90);
// this.cameras.main.startFollow(this.ship, true, 0.08, 0.08);
this.cameras.main.startFollow(this.ship, true);
this.cameras.main.setZoom(4);
}
updatePhysics ()
{
this.ship.setVelocity(0);
if (this.cursors.left.isDown)
{
this.ship.setAngle(-90).setVelocityX(-200);
}
else if (this.cursors.right.isDown)
{
this.ship.setAngle(90).setVelocityX(200);
}
if (this.cursors.up.isDown)
{
this.ship.setVelocityY(-200);
}
else if (this.cursors.down.isDown)
{
this.ship.setVelocityY(200);
}
}
update ()
{
if (this.cursors.left.isDown && this.ship.x > 0)
{
this.ship.setAngle(-90);
this.ship.x -= 2.5;
}
else if (this.cursors.right.isDown && this.ship.x < 3392)
{
this.ship.setAngle(90);
this.ship.x += 2.5;
}
if (this.cursors.up.isDown && this.ship.y > 0)
{
this.ship.y -= 2.5;
}
else if (this.cursors.down.isDown && this.ship.y < 240)
{
this.ship.y += 2.5;
}
}
}
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 загружаются необходимые ресурсы: спрайт корабля, JSON-описание тайловой карты и изображение с тайлами. Обратите внимание на использование setBaseURL для указания базового пути к ресурсам.
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('ship', 'assets/sprites/fmship.png');
this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/super-mario.json');
this.load.image('tiles1', 'assets/tilemaps/tiles/super-mario.png');
}
В методе create задаются ключевые параметры мира. Границы камеры (setBounds) определяют, как далеко она может двигаться. Границы физического мира (setBounds у this.physics.world) задают область, за пределы которой физические тела не могут выйти (хотя в данном примере физика для корабля отключена).
create ()
{
this.cameras.main.setBounds(0, 0, 3392, 100);
this.physics.world.setBounds(0, 0, 3392, 240);
}
Создание мира: тайловая карта и объект слежения
Создание игрового мира начинается с загрузки тайловой карты. Объект map создается через this.make.tilemap. Затем добавляется набор тайлов (addTilesetImage), где указывается ключ из данных Tiled и ключ загруженного изображения. Слой создается методом createLayer.
var map = this.make.tilemap({ key: 'map' });
var tileset = map.addTilesetImage('SuperMarioBros-World1-1', 'tiles1');
var layer = map.createLayer('World1', tileset, 0, 0);
Затем создается спрайт корабля — объект, за которым будет следовать камера. В исходном коде используется обычный спрайт (this.add.image), а закомментированная строка показывает, как создать физическое тело. Также настраивается управление с клавиатуры.
this.cursors = this.input.keyboard.createCursorKeys();
this.ship = this.add.image(400, 100, 'ship').setAngle(90);
Настройка поведения камеры: слежка и зум
Сердце примера — настройка камеры. Метод startFollow заставляет основную камеру следовать за целевым объектом. Первый аргумент — объект слежения. Второй аргумент (true) включает плавное (линейное) интерполирование движения камеры. Закомментированная версия показывает, как задать коэффициенты интерполяции по осям X и Y для более резкого или плавного движения.
this.cameras.main.startFollow(this.ship, true);
// this.cameras.main.startFollow(this.ship, true, 0.08, 0.08);
Метод setZoom изменяет масштаб отображения. Значение `4` увеличивает изображение в 4 раза, что полезно для пиксель-арт игр или чтобы показать детали объекта. При зуме камера продолжает следовать за целью в рамках своих границ.
this.cameras.main.setZoom(4);
Логика перемещения объекта
В примере представлены две функции обновления. updatePhysics не используется в текущей конфигурации, но демонстрирует, как управлять объектом через физическую систему Arcade, задавая скорость (setVelocity).
updatePhysics ()
{
this.ship.setVelocity(0);
if (this.cursors.left.isDown)
{
this.ship.setAngle(-90).setVelocityX(-200);
}
}
Активная функция update реализует простое перемещение корабля путем прямого изменения его координат (this.ship.x, this.ship.y). Проверка на границы мира (this.ship.x < 3392) предотвращает выход за пределы, заданные для камеры.
update ()
{
if (this.cursors.left.isDown && this.ship.x > 0)
{
this.ship.setAngle(-90);
this.ship.x -= 2.5;
}
}
Конфигурация игры
Конфигурационный объект config определяет основные параметры игры. Ключевые настройки для этого примера:
- pixelArt: true — включает сглаживание текстур для пиксель-арта.
- physics: { default: 'arcade' } — активирует физический движок Arcade (хотя в данном примере он не используется для корабля).
- scene: Example — указывает класс сцены.
const config = {
type: Phaser.AUTO,
parent: 'phaser-example',
width: 800,
height: 600,
pixelArt: true,
physics: {
default: 'arcade',
},
scene: Example
};
Что попробовать дальше
Вы освоили базовые принципы управления камерой в Phaser: задание границ, плавное слежение за целью и зум. Эти инструменты — фундамент для создания игр с прокруткой. Для экспериментов попробуйте: изменить коэффициент зума в зависимости от скорости объекта; использовать setDeadzone для того, чтобы камера начинала движение только когда объект уходит в крайнюю область экрана; или привязать камеру не к одному объекту, а к средней точке между несколькими игроками.
