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

При разработке игры с большим количеством графики управление сотнями отдельных файлов спрайтов превращается в кошмар. Phaser предлагает решение — мультиатласы. Этот метод позволяет объединить несколько файлов атласов (изображение + JSON с координатами) под одним ключом загрузки. В статье разберем, как это работает на практическом примере, и покажем, как упростить работу с графикой, загрузив несколько наборов спрайтов одной командой.

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

Живой запуск

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

Исходный код


class Scene extends Phaser.Scene
{
    constructor ()
    {
        super();
    }

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.path = 'assets/atlas/';

        this.load.multiatlas('megaset', 'tp3-multi-atlas.json');

        // this.load.image('megaset', 'assets/sprites/beer.png');

        this.load.on('filecomplete-multiatlas-megaset', () => {

            console.log('multi atlas loaded');

        });
    }

    create ()
    {
        //  This frame is in the 1st atlas file (set0/data0)
        this.add.image(0, 0, 'megaset', 'snake').setOrigin(0);

        //  This frame is in the 2nd atlas file (set1/data1)
        this.add.image(0, 100, 'megaset', 'nanoha-taiken-pink').setOrigin(0);

        //  This frame is in the 3rd atlas file (set2/data2)
        // this.add.image(0, 0, 'megaset', 'hello').setOrigin(0); // trimmed
        this.add.image(300, 130, 'megaset', 'bunny').setOrigin(0); // un-trimmed

        //  This frame is in the 4th atlas file (set3/data3)
        this.add.image(64, 300, 'megaset', 'contra3').setOrigin(0);
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    scene: Scene
}

new Phaser.Game(config);

Что такое мультиатлас и зачем он нужен

Обычный атлас — это один большой PNG-файл, содержащий множество спрайтов, и JSON-файл с координатами каждого из них. Мультиатлас (Multi Atlas) расширяет эту концепцию: это несколько пар PNG+JSON файлов, объединённых в один логический набор внутри Phaser.

Зачем это нужно? Представьте, что у вас есть графика для разных уровней или персонажей, созданная в разных папках или даже разными художниками. Вместо того чтобы загружать каждый атлас отдельно и отслеживать множество ключей, вы можете объединить их в один виртуальный атлас с общим ключом 'megaset'. Это существенно упрощает логику загрузки и доступ к спрайтам в коде.

Практика: загрузка мультиатласа

Загрузка происходит в методе preload(). Ключевой метод — load.multiatlas(). Первый аргумент — общий ключ для всего набора, второй — путь к специальному JSON-файлу, который описывает все отдельные атласы.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.path = 'assets/atlas/';

    this.load.multiatlas('megaset', 'tp3-multi-atlas.json');
}

В этом примере задаётся базовый URL и путь. Затем вызывается this.load.multiatlas('megaset', 'tp3-multi-atlas.json'). Phaser загрузит файл tp3-multi-atlas.json, прочитает из него список всех отдельных атласов (set0, set1 и т.д.) и загрузит соответствующие им PNG и JSON файлы. После завершения загрузки всего набора сработает событие filecomplete.

this.load.on('filecomplete-multiatlas-megaset', () => {
    console.log('multi atlas loaded');
});

Использование спрайтов из мультиатласа в сцене

После загрузки все спрайты из всех атласов становятся доступны по общему ключу 'megaset'. Неважно, в каком из исходных PNG-файлов находится нужный кадр (frame). Вы обращаетесь к нему, указывая ключ атласа и имя кадра.

create ()
{
    //  Кадр 'snake' находится в первом файле атласа (set0/data0)
    this.add.image(0, 0, 'megaset', 'snake').setOrigin(0);

    //  Кадр 'nanoha-taiken-pink' находится во втором файле атласа (set1/data1)
    this.add.image(0, 100, 'megaset', 'nanoha-taiken-pink').setOrigin(0);

    //  Кадр 'bunny' находится в третьем файле атласа (set2/data2)
    this.add.image(300, 130, 'megaset', 'bunny').setOrigin(0);

    //  Кадр 'contra3' находится в четвёртом файле атласа (set3/data3)
    this.add.image(64, 300, 'megaset', 'contra3').setOrigin(0);
}

Метод this.add.image() принимает координаты X, Y, ключ текстуры (это наш 'megaset') и имя кадра. Phaser сам находит, в каком из загруженных атласов находится кадр с указанным именем, и создаёт изображение. .setOrigin(0) устанавливает точку отсчёта (anchor) в левый верхний угол спрайта, что удобно для позиционирования от нулевых координат.

Структура JSON-файла для мультиатласа

Секрет в структуре файла tp3-multi-atlas.json. Это не обычный JSON от TexturePacker для одного атласа. Это мета-файл, который содержит массив textures. Каждый элемент этого массива — это путь к стандартному JSON-файлу отдельного атласа.

Примерное содержимое такого файла:

on
{
    "textures": [
        {
            "url": "set0.png",
            "json": "set0.json"
        },
        {
            "url": "set1.png",
            "json": "set1.json"
        }
        // ... и так далее
    ]
}

Phaser читает этот файл и для каждого элемента загружает указанные PNG (url) и JSON (json). Все кадры из всех этих атласов индексируются и становятся доступны под ключом, который вы указали первым аргументом в load.multiatlas() (в нашем случае 'megaset').

Плюсы, минусы и особенности

**Плюсы:** 1. **Упрощение кода:** Один ключ загрузки вместо нескольких. 2. **Логическая группировка:** Можно объединить арты по темам (например, 'gui', 'enemies', 'environment') в один мультиатлас. 3. **Удобство для художников:** Разные атласы можно готовить и обновлять независимо.

**Особенности и ограничения:** 1. **Уникальность имён кадров:** Имена кадров (frame names) во всех объединяемых атласах должны быть уникальными. Если в set0 и set1 есть кадр с именем 'hero', произойдёт коллизия, и один из них перезапишет другой. 2. **Загрузка всего набора:** Phaser не поддерживает частичную загрузку или выгрузку отдельных атласов из мультиатласа. Загружается весь набор, указанный в JSON. 3. **Инструменты:** Не все инструменты для создания атласов (например, старые версии TexturePacker) сразу экспортируют нужный для Phaser мультиатлас JSON. Возможно, структуру файла придётся собирать вручную или скриптом.

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

Мультиатласы в Phaser — это мощный инструмент для организации графики в больших проектах. Они позволяют сохранить гибкость работы с отдельными файлами атласов, предоставляя при этом единую точку доступа в коде. **Идеи для экспериментов:** 1. Попробуйте создать мультиатлас вручную, скомбинировав арты из разных источников. 2. Напишите скрипт (например, на Node.js), который автоматически генерирует JSON для мультиатласа, сканируя папку с вашими атласами. 3. Проверьте, как работает кэширование: загрузите мультиатлас, перейдите на другую сцену и создайте спрайты, используя тот же ключ 'megaset' — данные будут взяты из кэша.