О чем этот пример

Изометрическая графика придаёт игре глубину и уникальный визуальный стиль, часто ассоциирующийся с классическими RPG и стратегиями. Phaser предоставляет мощные инструменты для работы с тайловыми картами, позволяя быстро создавать сложные игровые миры. Эта статья покажет, как загрузить карту, созданную в редакторе Tiled, и корректно отобразить её слои, используя изометрическую проекцию. Вы научитесь настраивать камеру для плавного перемещения по большой карте.

Версия 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.image('tiles', 'assets/tilemaps/iso/iso-64x64-outside.png');
        this.load.image('tiles2', 'assets/tilemaps/iso/iso-64x64-building.png');
        this.load.tilemapTiledJSON('map', 'assets/tilemaps/iso/isorpg.json');
    }

    create ()
    {
        const map = this.add.tilemap('map');

        console.log(map);

        const tileset1 = map.addTilesetImage('iso-64x64-outside', 'tiles');
        const tileset2 = map.addTilesetImage('iso-64x64-building', 'tiles2');

        const layer1 = map.createLayer('Tile Layer 1', [ tileset1, tileset2 ]);
        const layer2 = map.createLayer('Tile Layer 2', [ tileset1, tileset2 ]);
        const layer3 = map.createLayer('Tile Layer 3', [ tileset1, tileset2 ]);
        const layer4 = map.createLayer('Tile Layer 4', [ tileset1, tileset2 ]);
        const layer5 = map.createLayer('Tile Layer 5', [ tileset1, tileset2 ]);

        const cursors = this.input.keyboard.createCursorKeys();

        this.cameras.main.setZoom(2);

        const controlConfig = {
            camera: this.cameras.main,
            left: cursors.left,
            right: cursors.right,
            up: cursors.up,
            down: cursors.down,
            acceleration: 0.04,
            drag: 0.0005,
            maxSpeed: 0.7
        };

        this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);
    }

    update (time, delta)
    {
        this.controls.update(delta);
    }
}

const config = {
    type: Phaser.WEBGL,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    pixelArt: true,
    scene: Example
};

const game = new Phaser.Game(config);

Загрузка ресурсов: карта и тайлсеты

Первый шаг — подготовка всех необходимых ресурсов в методе preload. В примере загружаются два изображения с тайлами и сам файл карты в формате JSON, экспортированный из Tiled.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('tiles', 'assets/tilemaps/iso/iso-64x64-outside.png');
    this.load.image('tiles2', 'assets/tilemaps/iso/iso-64x64-building.png');
    this.load.tilemapTiledJSON('map', 'assets/tilemaps/iso/isorpg.json');
}

Метод setBaseURL задаёт базовый путь для всех последующих загрузок, что удобно при использовании удалённых ресурсов. load.image загружает PNG-файлы, содержащие наборы тайлов (спрайты для земли, зданий и т.д.). Ключи 'tiles' и 'tiles2' будут использоваться для ссылки на эти изображения внутри Phaser. load.tilemapTiledJSON загружает саму структуру карты, созданную во внешнем редакторе.

Создание и настройка тайловой карты

В методе create происходит основная работа по сборке мира из загруженных данных.

const map = this.add.tilemap('map');
const tileset1 = map.addTilesetImage('iso-64x64-outside', 'tiles');
const tileset2 = map.addTilesetImage('iso-64x64-building', 'tiles2');

this.add.tilemap('map') создаёт объект тайловой карты, используя данные из JSON-файла. Затем необходимо связать имена тайлсетов, указанные в редакторе Tiled ('iso-64x64-outside'), с ключами загруженных изображений ('tiles'). Это делает метод map.addTilesetImage. В данном примере карта использует два набора тайлов.

Слои карты: от фона к переднему плану

Карта из Tiled состоит из слоёв, которые отрисовываются в определённом порядке.

const layer1 = map.createLayer('Tile Layer 1', [ tileset1, tileset2 ]);
const layer2 = map.createLayer('Tile Layer 2', [ tileset1, tileset2 ]);
const layer3 = map.createLayer('Tile Layer 3', [ tileset1, tileset2 ]);
const layer4 = map.createLayer('Tile Layer 4', [ tileset1, tileset2 ]);
const layer5 = map.createLayer('Tile Layer 5', [ tileset1, tileset2 ]);

Метод map.createLayer создаёт и отображает слой по его имени, указанному в Tiled. Второй аргумент — массив тайлсетов, которые могут использоваться в этом слое. Порядок создания слоев важен: layer1 (нижний слой, например, земля) будет отрисован первым, а layer5 (верхний слой, например, крыши деревьев) — поверх всех остальных. Это создаёт естественную глубину.

Управление камерой: плавное перемещение по миру

Изометрическая карта часто больше экрана, поэтому нужна камера для навигации.

this.cameras.main.setZoom(2);

const cursors = this.input.keyboard.createCursorKeys();

const controlConfig = {
    camera: this.cameras.main,
    left: cursors.left,
    right: cursors.right,
    up: cursors.up,
    down: cursors.down,
    acceleration: 0.04,
    drag: 0.0005,
    maxSpeed: 0.7
};

this.controls = new Phaser.Cameras.Controls.SmoothedKeyControl(controlConfig);

setZoom(2) увеличивает вид камеры в два раза, так как изометрические тайлы могут быть крупными. createCursorKeys создаёт объект для отслеживания нажатий стрелок. Phaser.Cameras.Controls.SmoothedKeyControl — это удобный контроллер, который делает движение камеры плавным, с ускорением (acceleration) и инерцией (drag). Он обновляется каждый кадр в методе update.

update (time, delta)
{
    this.controls.update(delta);
}

Конфигурация игры и запуск

Финальный шаг — настройка объекта конфигурации и создание экземпляра игры.

const config = {
    type: Phaser.WEBGL,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    pixelArt: true,
    scene: Example
};

const game = new Phaser.Game(config);

Ключевые параметры: type: Phaser.WEBGL использует аппаратное ускорение. pixelArt: true включает специальный режим фильтрации пиксельной графики, который предотвращает размытие тайлов при масштабировании. Параметр scene указывает на основной класс сцены, который содержит всю логику, описанную выше.

Что попробовать дальше

Вы успешно разобрали пример создания изометрического мира в Phaser. Основной принцип — разделение данных (JSON из Tiled) и их визуального представления (тайлсеты). Для экспериментов попробуйте: изменить параметры acceleration и drag у контроллера камеры для другого "ощущения" движения; добавить слой с объектами (objects layer) из Tiled для размещения персонажей или точек взаимодействия; поэкспериментировать с setZoom и размерами холста (width, height) для создания различных видов камеры.