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

При создании 2D-изометрических игр или проектов с кастомной графикой порядок, в котором тайлы отрисовываются на экране, критически важен для корректного отображения. Неправильный порядок может привести к визуальным артефактам, когда одни объекты неожиданно перекрывают другие. Этот пример демонстрирует, как использовать мощный, но часто упускаемый из виду метод `setRenderOrder()` для полного контроля над рендерингом тайловых слоёв, обеспечивая безупречный визуальный результат.

Версия Phaser: код и демо в этой статье рассчитаны на Phaser 3.90.0.

Живой запуск

Ниже встроен рабочий билд примера. Оригинальный источник: GitHub.

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('tileset', 'assets/tilemaps/tiles/tileorder.png');
        this.load.tilemapTiledJSON('map', 'assets/tilemaps/maps/tileorder.json');
    }

    create ()
    {
        this.cameras.main.scrollX = 120;
        this.cameras.main.scrollY = 80;
        this.cameras.main.zoom = 2;

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

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

        const layer1 = map.createLayer('floor', tiles, 0, 0);
        const layer2 = map.createLayer('objects', tiles, 0, 0);

        let renderOrder = 1;

        const text = this.add.text(340, 250, 'Render Order: left-down');

        this.input.on('pointerup', () =>
        {

            renderOrder++;

            if (renderOrder === 4)
            {
                renderOrder = 0;
            }

            layer1.setRenderOrder(renderOrder);
            layer2.setRenderOrder(renderOrder);

            const orders = [
                'right-down',
                'left-down',
                'right-up',
                'left-up'
            ];

            text.setText(`Render Order: ${orders[renderOrder]}`);

        });
    }
}

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

const game = new Phaser.Game(config);

Суть проблемы рендеринга

По умолчанию Phaser отрисовывает тайлы на слое в порядке «слева-направо, сверху-вниз» (left-down). Этот порядок идеален для стандартных видов сверху или сбоку. Однако для изометрических проектов или определённых художественных стилей такой порядок может привести к тому, что задние объекты будут отрисованы поверх передних, ломая восприятие глубины.

Метод setRenderOrder() класса TilemapLayer позволяет переопределить этот алгоритм. Мы управляем последовательностью, в которой рендерер «обходит» тайлы на слое, прежде чем отправить их на отрисовку.

Настройка сцены и загрузка карты

Код начинается с базовой настройки. Обратите внимание на использование pixelArt: true в конфигурации игры — это предотвращает размытие пиксельной графики.

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

В create() мы сразу настраиваем камеру: сдвигаем её и увеличиваем зум, чтобы лучше видеть демонстрационный эффект. Затем создаём объект тайловой карты и добавляем к ней загруженный тайлсет.

// Настройка камеры для удобного просмотра
this.cameras.main.scrollX = 120;
this.cameras.main.scrollY = 80;
this.cameras.main.zoom = 2;

// Создание карты и тайлсета
const map = this.make.tilemap({ key: 'map' });
const tiles = map.addTilesetImage('tileset', 'tileset');

Создание слоёв и управление порядком

Из карты создаются два слоя: «floor» (пол) и «objects» (объекты). Изначально они отрисовываются в порядке, заданном в редакторе Tiled и по умолчанию в Phaser.

Ключевой элемент примера — переменная renderOrder и обработчик клика мыши. При каждом клике значение renderOrder увеличивается, а по достижении максимума сбрасывается на ноль. Это значение передаётся в метод setRenderOrder() для обоих слоёв.

const layer1 = map.createLayer('floor', tiles, 0, 0);
const layer2 = map.createLayer('objects', tiles, 0, 0);

let renderOrder = 1;

// Применение нового порядка отрисовки к слоям
layer1.setRenderOrder(renderOrder);
layer2.setRenderOrder(renderOrder);

Четыре режима отрисовки

Phaser предоставляет четыре предустановленных алгоритма порядка рендеринга, соответствующие индексам от 0 до 3. В коде они сопоставлены с понятными названиями в массиве orders. Метод setRenderOrder() принимает именно этот числовой индекс.

* **0 — right-down:** Отрисовка по строкам, слева-направо, сверху-вниз (стандартный для многих систем). * **1 — left-down:** Отрисовка по строкам, справа-налево, сверху-вниз (дефолтный в Phaser). * **2 — right-up:** Отрисовка по строкам, слева-направо, снизу-вверх. * **3 — left-up:** Отрисовка по строкам, справа-налево, снизу-вверх.

Изменение этого параметра мгновенно перестраивает порядок отрисовки всех тайлов на слое без необходимости перезаписывать саму карту.

const orders = [
    'right-down',
    'left-down',
    'right-up',
    'left-up'
];
text.setText(`Render Order: ${orders[renderOrder]}`);

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

Метод setRenderOrder() — это точный инструмент для решения специфических визуальных проблем в тайловых играх. Он незаменим для изометрии, кастомных перспектив или сложных декораций, где важен контроль над глубиной. Попробуйте применить его в своих проектах: создайте слой с деревьями и зданиями и поэкспериментируйте с порядком, чтобы добиться идеального перекрытия спрайтов игрока. Можно даже написать кастомную функцию сортировки, если стандартных четырёх режимов окажется недостаточно для вашей художественной задумки.