О чем этот пример
В Phaser можно создавать изометрические уровни не только из готовых JSON-файлов, но и генерировать их прямо в коде. Этот подход полезен, когда вам нужна динамическая генерация локаций, процедурно создаваемые миры или просто полный контроль над каждым тайлом на карте. В статье разберем, как создать изометрический тайлмап с нуля, используя только API 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('tiles', 'assets/tilemaps/iso/iso-64x64-outside.png');
}
create ()
{
const mapData = new Phaser.Tilemaps.MapData({
width: 10,
height: 10,
tileWidth: 64,
tileHeight: 32,
orientation: Phaser.Tilemaps.Orientation.ISOMETRIC,
format: Phaser.Tilemaps.Formats.ARRAY_2D
});
const map = new Phaser.Tilemaps.Tilemap(this, mapData);
const tileset = map.addTilesetImage('iso-64x64-outside', 'tiles');
const layer = map.createBlankLayer('layer', tileset, 350, 200);
const data = [
[ 10, 11, 12, 13, 14, 15, 16, 10, 11, 12 ],
[ 13, 11, 10, 12, 12, 15, 16, 10, 16, 10 ],
[ 12, 10, 16, 13, 14, 15, 16, 16, 13, 12 ],
[ 10, 11, 12, 13, 14, 15, 16, 10, 11, 12 ],
[ 13, 11, 10, 12, 12, 15, 16, 10, 16, 10 ],
[ 12, 10, 16, 13, 14, 15, 16, 16, 13, 12 ],
[ 10, 11, 12, 13, 14, 15, 16, 10, 11, 12 ],
[ 13, 11, 10, 12, 12, 15, 16, 10, 16, 10 ],
[ 12, 10, 16, 13, 14, 15, 16, 16, 13, 12 ],
[ 10, 11, 12, 13, 14, 15, 16, 10, 11, 12 ]
];
let y = 0;
data.forEach(row => {
row.forEach((tile, x) => {
layer.putTileAt(tile, x, y);
});
y++;
});
}
}
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
pixelArt: true,
scene: Example
};
const game = new Phaser.Game(config);
Подготовка данных карты: Phaser.Tilemaps.MapData
Первый шаг — создать объект MapData, который хранит основные параметры карты. Ключевой параметр здесь — orientation: Phaser.Tilemaps.Orientation.ISOMETRIC. Именно он сообщает движку, что мы работаем с изометрической проекцией, а не с ортогональной.
const mapData = new Phaser.Tilemaps.MapData({
width: 10,
height: 10,
tileWidth: 64,
tileHeight: 32,
orientation: Phaser.Tilemaps.Orientation.ISOMETRIC,
format: Phaser.Tilemaps.Formats.ARRAY_2D
});
Обратите внимание на размеры тайлов: tileWidth (64) больше tileHeight (32). Это характерно для изометрических тайлов, где ромбовидный тайл шире, чем высота. Параметр format указывает, что данные слоя будут представлены в виде двумерного массива.
Создание тайлмапа, тайлсета и слоя
На основе MapData создается объект тайлмапа. Затем загруженное изображение тайлов добавляется в тайлсет карты. Важно: имя тайлсета ('iso-64x64-outside') должно совпадать с ключом, который вы будете использовать для ссылки на эти тайлы в данных карты.
const map = new Phaser.Tilemaps.Tilemap(this, mapData);
const tileset = map.addTilesetImage('iso-64x64-outside', 'tiles');
Далее создается пустой слой, привязанный к этому тайлсету. Аргументы 350 и 200 — это координаты (x, y) на экране, откуда начнется отрисовка слоя. Это позволяет позиционировать всю карту на сцене.
const layer = map.createBlankLayer('layer', tileset, 350, 200);
Заполнение слоя данными из массива
Содержимое карты определяется двумерным массивом data. Каждое число в массиве — это глобальный индекс тайла в тайлсете. Индексация начинается с 0, но в примере используются числа от 10, что означает использование тайлов, начиная с 10-й позиции в тайлсете.
const data = [
[ 10, 11, 12, 13, 14, 15, 16, 10, 11, 12 ],
// ... остальные строки
];
Для заполнения слоя используется двойной цикл. Метод layer.putTileAt(tile, x, y) помещает тайл с индексом tile в позицию (x, y) на слое.
let y = 0;
data.forEach(row => {
row.forEach((tile, x) => {
layer.putTileAt(tile, x, y);
});
y++;
});
Важно: координаты (x, y) здесь — это координаты в сетке тайлмапа (матрица 10x10), а не пиксельные координаты на экране. Phaser сам рассчитает правильное изометрическое положение каждого тайла на основе параметров MapData.
Конфигурация игры и важная настройка
Для корректного отображения пиксельной графики, к которой часто относятся тайлсеты, в конфиге игры установлен флаг pixelArt: true. Это отключает сглаживание текстуры при масштабировании, сохраняя четкие края тайлов.
const config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
pixelArt: true,
scene: Example
};
Без этой настройки тайлы могут выглядеть размытыми, особенно если разрешение игры или масштаб камеры не кратны размеру тайлов.
Что попробовать дальше
Ручное создание изометрического тайлмапа через код дает разработчику гибкость. Вы можете генерировать данные карты алгоритмически, подгружать их с сервера или менять в реальном времени. Для экспериментов попробуйте:
1. Изменить массив data в реальном времени по клику мыши, используя layer.putTileAt.
2. Сгенерировать процедурную карту, используя шум Перлина или простые правила (например, случайные индексы тайлов).
3. Добавить несколько слоев (createBlankLayer) для создания эффекта глубины (земля, трава, декорации).
4. Использовать метод worldToTileXY из Phaser.Tilemaps.Tilemap для преобразования пиксельных координат мыши в координаты тайла на изометрической сетке.
