Тайлмапы
Загрузка карт Tiled в формате JSON, отрисовка слоёв, построение столкновений и изменение тайлов во время выполнения.
Система тайлмапов Phaser 4 читает JSON-экспорты из Tiled. Вы создаёте карту во внешнем редакторе, а Phaser берёт на себя отрисовку, столкновения и изменение во время выполнения.
Загрузка карты Tiled
Задействованы два файла: JSON карты и изображение тайлсета, на которое она ссылается.
preload() {
this.load.tilemapTiledJSON('level-1', 'assets/maps/level-1.json');
this.load.image('tiles', 'assets/tilesets/world.png');
}
Затем собираем карту и её слои:
create() {
const map = this.make.tilemap({ key: 'level-1' });
// Первый аргумент — имя тайлсета *как оно задано в Tiled*; второй —
// ключ кэша загруженного изображения. Часто они совпадают.
const tileset = map.addTilesetImage('world', 'tiles');
const ground = map.createLayer('Ground', tileset, 0, 0);
const walls = map.createLayer('Walls', tileset, 0, 0);
const decor = map.createLayer('Decor', tileset, 0, 0);
}
Третий и четвёртый аргументы — мировые координаты левого верхнего угла слоя, обычно 0, 0.
Столкновения
Три идиоматичных способа отметить, какие тайлы участвуют в столкновениях:
// 1. По индексу тайла — точные ID тайлов из тайлсета.
walls.setCollision([12, 13, 25, 26]);
// 2. По диапазону.
walls.setCollisionBetween(1, 99);
// 3. По пользовательскому свойству Tiled — лучший вариант, если вы управляете источником.
walls.setCollisionByProperty({ collides: true });
Затем добавляем коллайдер:
this.physics.add.collider(player, walls);
Для односторонних платформ, склонов и других столкновений с учётом угла см. справочник API Tilemaps — методы TilemapLayer.setCollision* и специфичный для Arcade TileCollisionGroup покрывают большинство случаев.
Слои объектов
Слои объектов Tiled — это канонический способ размещать игровые маркеры: точку появления игрока, позиции врагов, двери. Они приходят в виде списка обычных объектов:
const spawns = map.getObjectLayer('Spawns');
spawns?.objects.forEach((obj) => {
switch (obj.name) {
case 'player': this.player = this.physics.add.sprite(obj.x!, obj.y!, 'player'); break;
case 'enemy': this.enemies.create(obj.x!, obj.y!, 'enemy'); break;
}
});
Свойство properties каждого объекта несёт пользовательские свойства Tiled в виде записей {name, type, value} — если вы часто с ними работаете, упростите доступ небольшим хелпером, разворачивающим их в плоский объект.
Границы камеры
Почти всегда привязывайте карту к камере:
this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
this.physics.world.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
this.cameras.main.startFollow(this.player);
Без этого камера будет спокойно прокручиваться за края карты в пустоту.
Изменение во время выполнения
Слои предоставляют прямой доступ к тайлам:
const tile = walls.getTileAtWorldXY(player.x, player.y - 32);
if (tile?.properties.breakable) {
walls.removeTileAt(tile.x, tile.y);
}
// Заменяем каждый экземпляр одного тайла на другой.
ground.swapByIndex(45, 67);
// Прорезаем линию из тайлов.
for (let x = 0; x < 8; x++) walls.putTileAt(12, startX + x, startY);
Обратите внимание: координаты тайлов здесь — это тайловое пространство (0, 0 — это левый верхний тайл), а не пиксели. Используйте варианты WorldXY, когда у вас пиксельные координаты, и индексные варианты, когда у вас тайловые координаты.
Производительность
- Статические слои дёшевы. Phaser батчирует слой в один или несколько вызовов отрисовки. Карта 200×200 отрисовывается практически бесплатно.
- Свойства по тайлам стоят времени поиска. Если вы обнаружили, что перебираете каждый тайл каждый кадр, кэшируйте результат.
- Отсечение (culling) включено по умолчанию. Тайлы за пределами камеры пропускаются. Не отключайте отсечение, не проведя сначала замеры.
Связанное
- Arcade-физика — как разрешаются столкновения с тайлами.
- Камеры — установка границ под размер карты.
- Загрузчик и ассеты — загрузчики
tilemapTiledJSONи изображений.