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

Создание больших игровых уровней вручную — трудоёмкая задача. Тайловые карты (Tilemaps) позволяют быстро собирать локации из повторяющихся элементов, как из конструктора. Этот подход экономит время и ресурсы, особенно для платформеров, 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/tiles/cybernoid.png');
        this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/cybernoid.json');
    }

    create ()
    {
        const map = this.make.tilemap({ key: 'map' });

        const tiles = map.addTilesetImage('cybernoid', 'tiles');

        const layer = map.createLayer(0, tiles, 0, 0);

        this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);

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

        const controlConfig = {
            camera: this.cameras.main,
            left: cursors.left,
            right: cursors.right,
            up: cursors.up,
            down: cursors.down,
            speed: 0.5
        };

        this.controls = new Phaser.Cameras.Controls.FixedKeyControl(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(). Здесь мы загружаем два ключевых ресурса: изображение с набором тайлов (tileset) и сам файл карты в формате JSON, экспортированный из Tiled.

Метод this.load.setBaseURL() устанавливает базовый URL, от которого будут строиться пути к файлам. Это удобно, если все ваши ассеты лежат в одной папке на сервере.

this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('tiles', 'assets/tilemaps/tiles/cybernoid.png');
this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/cybernoid.json');

Обратите внимание: первый параметр в load.image и load.tilemapTiledJSON — это ключ (key), по которому мы будем обращаться к загруженному ресурсу позже. Второй параметр — относительный путь к файлу.

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

В методе create() происходит магия превращения данных в видимый уровень. Сначала на основе загруженного JSON создаётся объект тайловой карты.

const map = this.make.tilemap({ key: 'map' });

Затем необходимо связать тайлсет из JSON с загруженным изображением. В нашем примере тайлсет внутри файла cybernoid.json имеет имя 'cybernoid'. Мы говорим движку: «Возьми данные тайлсета с ключом 'cybernoid' и используй для них изображение с ключом 'tiles'».

const tiles = map.addTilesetImage('cybernoid', 'tiles');

После этого можно создать визуальный слой. Метод map.createLayer() принимает индекс слоя (в данном случае 0 — первый слой), связанный тайлсет и координаты отрисовки.

const layer = map.createLayer(0, tiles, 0, 0);

Настройка камеры и управление

Размер уровня часто превышает размер игрового окна. Чтобы игрок мог исследовать мир, нужна камера, которая будет следить за героем или, как в нашем случае, которую можно двигать вручную.

Сначала мы устанавливаем границы камеры, равные размерам всей карты в пикселях. Это не даст камере выйти за пределы уровня.

this.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);

Далее создаём объект управления FixedKeyControl. Для этого нам нужна конфигурация, которая свяжет клавиши-стрелки с перемещением камеры.

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

const controlConfig = {
    camera: this.cameras.main,
    left: cursors.left,
    right: cursors.right,
    up: cursors.up,
    down: cursors.down,
    speed: 0.5
};

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

Параметр speed определяет, насколько быстро камера будет реагировать на нажатие клавиш. Чтобы управление работало, объект controls необходимо обновлять каждый кадр в методе update().

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

Важные нюансы конфигурации

Конфиг игры содержит два важных для работы с пиксельной графикой и тайловыми картами свойства.

const config = {
    // ... другие настройки
    pixelArt: true,
    scene: Example
};

Установка pixelArt: true отключает сглаживание при масштабировании изображений. Это критически важно для сохранения чёткого вида пиксельной графики. Без этой настройки тайлы будут размытыми.

Сцена Example передаётся в конфиг, чтобы Phaser знал, какой класс содержит нашу игровую логику.

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

Теперь у вас есть полностью рабочая сцена с загруженной тайловой картой и камерой, которой можно управлять стрелками. Это основа для многих типов игр. Для экспериментов попробуйте: заменить карту и тайлсет на свои; добавить несколько слоёв (например, для фона и декораций); создать спрайт игрока и заставить камеру следовать за ним, используя this.cameras.main.startFollow(sprite). Это откроет путь к созданию полноценных игровых миров.