О чем этот пример
В разработке игр часто требуется выходить за рамки статичного уровня. Этот пример демонстрирует, как динамически управлять размером слоя тайловой карты и настраивать камеру для плавного скроллинга. Вы научитесь программно изменять геометрию игрового мира и привязывать к ней виртуальную камеру, что является основой для создания расширяемых уровней или эффектов "растягивания" мира.
Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.
Живой запуск
Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.
Исходный код
class Example extends Phaser.Scene
{
controls;
preload ()
{
this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/super-mario.json');
this.load.image('tiles', 'assets/tilemaps/tiles/super-mario.png');
}
create ()
{
const map = this.make.tilemap({ key: 'map' });
const tileset = map.addTilesetImage('SuperMarioBros-World1-1', 'tiles');
const layer = map.createLayer('World1', tileset, 0, 0);
layer.width = 200;
const cursors = this.input.keyboard.createCursorKeys();
const controlConfig = {
camera: this.cameras.main,
left: cursors.left,
right: cursors.right,
speed: 0.5
};
this.controls = new Phaser.Cameras.Controls.FixedKeyControl(controlConfig);
this.cameras.main.setBounds(0, 0, layer.x + layer.width, 0);
}
update (time, delta)
{
this.controls.update(delta);
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Загрузка ресурсов и создание карты
В методе preload() загружаются два ключевых ресурса: JSON-файл с данными карты, созданный в Tiled Editor, и изображение с тайлами.
this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/super-mario.json');
this.load.image('tiles', 'assets/tilemaps/tiles/super-mario.png');
В create() происходит инициализация игрового мира. Сначала создается объект тайловой карты (Tilemap), затем он связывается с загруженным изображением тайлов через addTilesetImage. После этого создается визуальный слой (TilemapLayer), который и отрисовывается на сцене.
const map = this.make.tilemap({ key: 'map' });
const tileset = map.addTilesetImage('SuperMarioBros-World1-1', 'tiles');
const layer = map.createLayer('World1', tileset, 0, 0);
Динамическое изменение ширины слоя
Самая важная строка в этом примере — модификация свойства width созданного слоя. Исходная ширина слоя определяется загруженной картой. Присвоив новое значение, мы искусственно "растягиваем" игровой мир. Физические границы и отрисовка тайлов при этом не меняются, но изменяется пространство, по которому может перемещаться камера.
layer.width = 200;
Это мощный прием для создания иллюзии большего мира или для динамической подстройки уровня под игровые события. Важно помнить, что это изменение виртуальное и не добавляет новые тайлы.
Настройка управления камерой
Для перемещения по увеличенному миру нужен инструмент управления камерой. Сначала создается объект для отслеживания нажатий стрелок клавиатуры.
const cursors = this.input.keyboard.createCursorKeys();
Затем создается конфигурация для встроенного контроллера камеры FixedKeyControl. В конфиге указывается, какая камера управляется (this.cameras.main), какие клавиши отвечают за движение влево и вправо, и скорость перемещения.
const controlConfig = {
camera: this.cameras.main,
left: cursors.left,
right: cursors.right,
speed: 0.5
};
this.controls = new Phaser.Cameras.Controls.FixedKeyControl(controlConfig);
Установка границ для камеры
Чтобы камера не выходила за пределы игрового мира, необходимо задать её границы с помощью метода setBounds. Ключевой момент расчета: правая граница (width) устанавливается как сумма начальной позиции слоя по X (layer.x) и его новой, увеличенной ширины (layer.width).
this.cameras.main.setBounds(0, 0, layer.x + layer.width, 0);
Поскольку в этом примере скроллинг только горизонтальный, границы по высоте (Y и height) установлены в 0. Камера будет плавно перемещаться в рамках рассчитанной ширины, позволяя игроку осмотреть весь "растянутый" слой.
Обновление состояния контроллера
Логика перемещения камеры, заложенная в контроллере FixedKeyControl, должна обновляться каждый кадр. Для этого в методе update() вызывается его метод update, куда передается delta-время — разница в миллисекундах с предыдущим кадром. Это обеспечивает плавное и независимое от частоты кадров движение.
update (time, delta)
{
this.controls.update(delta);
}
Что попробовать дальше
Пример показывает простой, но эффективный способ трансформации игрового пространства через изменение свойств слоя тайловой карты и корректную настройку камеры. Для экспериментов попробуйте изменить layer.width в зависимости от действий игрока, реализовать вертикальный скроллинг, добавив управление по оси Y, или анимировать изменение ширины для создания эффекта "разворачивающегося" уровня.
