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

При разработке игр под браузер важно не только качество графики, но и скорость загрузки контента. Phaser 3 предоставляет мощный инструмент для загрузки текстур — `load.texture()`, который позволяет автоматически выбирать оптимальный формат изображения в зависимости от поддержки браузером. Этот подход значительно сокращает размер загружаемых файлов и повышает производительность, особенно на мобильных устройствах. В этой статье мы разберем практический пример загрузки сжатого мультиатласа текстур, который подключает разные форматы (ASTC, ETC, PVRTC, S3TC) и автоматически выбирает подходящий. Вы узнаете, как настроить такую систему в своем проекте и какие преимущества она дает.

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

Живой запуск

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

Исходный код


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

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

        this.load.texture('test', {
            'ASTC': { type: 'PVR', multiAtlasURL: `${path}/uncompressed/multi-ASTC-4x4-lRGB.json`, multiPath: `${path}/compressed` },
            'ETC': { type: 'PVR', multiAtlasURL: `${path}/uncompressed/multi-ETC2-lRGB.json`, multiPath: `${path}/compressed` },
            'PVRTC': { type: 'PVR', multiAtlasURL: `${path}/uncompressed/multi-PVRTC-4BPP-lRGB.json`, multiPath: `${path}/compressed` },
            'S3TC': { type: 'PVR', multiAtlasURL: `${path}/uncompressed/multi-S3TC-BC3-lRGB.json`, multiPath: `${path}/compressed` },
            'IMG': { multiAtlasURL: `${path}/uncompressed/multi.json`, multiPath: `${path}/uncompressed/multi.json` }
        });
    }

    create ()
    {
        this.add.sprite(400, 250, 'test', 'phaser3-logo-x2');
        this.add.sprite(400, 100, 'test', 'astorm-truck');
        this.add.sprite(400, 420, 'test', 'bunny');
    }
}

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    backgroundColor: '#2d2d6d',
    scene: Demo
};

const game = new Phaser.Game(config);

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

Мультиатлас — это набор нескольких текстур (спрайтов), объединенных в один большой файл изображения и описанный в JSON-файле. Такой подход уменьшает количество HTTP-запросов и оптимизирует рендеринг.

Сжатые текстуры (ASTC, ETC, PVRTC, S3TC) — это форматы, которые уменьшают объем видеопамяти (VRAM), занимаемый графикой. Они особенно важны для мобильных устройств и веб-игр, где ресурсы ограничены. Phaser позволяет загружать несколько вариантов одного атласа, каждый в своем формате, и автоматически выбирать тот, который поддерживается браузером пользователя.

this.load.texture('test', {
    'ASTC': { type: 'PVR', multiAtlasURL: `${path}/uncompressed/multi-ASTC-4x4-lRGB.json`, multiPath: `${path}/compressed` },
    'ETC': { type: 'PVR', multiAtlasURL: `${path}/uncompressed/multi-ETC2-lRGB.json`, multiPath: `${path}/compressed` }
});

Настройка загрузки в методе preload

В методе preload() сценария мы настраиваем базовый URL для загрузки ресурсов и определяем конфигурацию для ключа 'test'. Объект конфигурации содержит свойства, имена которых соответствуют форматам текстур ('ASTC', 'ETC', 'PVRTC', 'S3TC', 'IMG'). Каждое свойство — это объект с параметрами загрузки.

Ключевые параметры: - type: указывает тип текстуры (например, 'PVR' для форматов, использующих технологию PVR). - multiAtlasURL: путь к JSON-файлу, который описывает мультиатлас (содержит координаты и размеры каждого спрайта). - multiPath: базовый путь к самим изображениям (файлам .pvr или .png).

Формат 'IMG' используется как fallback — это обычный PNG-атлас, который будет загружен, если браузер не поддерживает ни один из сжатых форматов.

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

    this.load.texture('test', {
        'ASTC': { type: 'PVR', multiAtlasURL: `${path}/uncompressed/multi-ASTC-4x4-lRGB.json`, multiPath: `${path}/compressed` },
        'ETC': { type: 'PVR', multiAtlasURL: `${path}/uncompressed/multi-ETC2-lRGB.json`, multiPath: `${path}/compressed` },
        'PVRTC': { type: 'PVR', multiAtlasURL: `${path}/uncompressed/multi-PVRTC-4BPP-lRGB.json`, multiPath: `${path}/compressed` },
        'S3TC': { type: 'PVR', multiAtlasURL: `${path}/uncompressed/multi-S3TC-BC3-lRGB.json`, multiPath: `${path}/compressed` },
        'IMG': { multiAtlasURL: `${path}/uncompressed/multi.json`, multiPath: `${path}/uncompressed/multi.json` }
    });
}

Использование загруженных текстур в create

После успешной загрузки текстуру можно использовать по ее ключу 'test'. В методе create() мы создаем три спрайта, обращаясь к одному и тому же атласу, но указывая разные имена кадров (frames). Phaser автоматически выберет правильный источник (сжатый или несжатый) на основе возможностей системы.

- 'phaser3-logo-x2', 'astorm-truck', 'bunny' — это имена отдельных спрайтов внутри мультиатласа, которые были определены в JSON-файле. - this.add.sprite(400, 250, 'test', 'phaser3-logo-x2') создает спрайт в координатах (400, 250), используя текстуру 'test' и кадр 'phaser3-logo-x2'.

create ()
{
    this.add.sprite(400, 250, 'test', 'phaser3-logo-x2');
    this.add.sprite(400, 100, 'test', 'astorm-truck');
    this.add.sprite(400, 420, 'test', 'bunny');
}

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

Конфигурационный объект игры определяет основные параметры, такие как тип рендерера, размеры холста, фон и главную сцену. В данном примере используется Phaser.AUTO для автоматического выбора между WebGL и Canvas.

- parent: 'phaser-example' указывает ID HTML-элемента, в который будет встроен canvas игры. - width и height задают размеры области отрисовки. - backgroundColor устанавливает цвет фона сцены в шестнадцатеричном формате. - scene: Demo передает класс нашей сцены, которая будет запущена сразу после инициализации игры.

Создание экземпляра Phaser.Game с этой конфигурацией запускает весь процесс.

const config = {
    type: Phaser.AUTO,
    parent: 'phaser-example',
    width: 800,
    height: 600,
    backgroundColor: '#2d2d6d',
    scene: Demo
};

const game = new Phaser.Game(config);

Практические советы по использованию

1. **Подготовка текстур**: Для генерации сжатых мультиатласов используйте инструменты вроде TexturePacker или shoebox. Убедитесь, что вы экспортируете атласы во всех необходимых форматах и создаете JSON-файлы с корректными путями.

2. **Структура папок**: В примере папка assets/compressed содержит подпапки compressed (для сжатых .pvr файлов) и uncompressed (для JSON-описаний и PNG-атласа). Поддерживайте четкую структуру, чтобы пути в коде оставались простыми.

3. **Fallback стратегия**: Всегда включайте вариант 'IMG' с обычными PNG. Это гарантирует, что игра будет работать даже в старых браузерах, пусть и с большим объемом загрузки.

4. **Отладка**: Чтобы проверить, какой формат был загружен, используйте console.log(this.textures.get('test').source[0].compression) после create().

// Пример проверки загруженного формата
create ()
{
    const texture = this.textures.get('test');
    console.log(texture.source[0].compression); // Выведет 'ASTC', 'ETC' и т.д.
}

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

Использование load.texture() с поддержкой нескольких сжатых форматов — это профессиональный подход к управлению графикой в Phaser. Он позволяет значительно сократить время загрузки и потребление памяти без ущерба для качества. Вы можете экспериментировать с добавлением новых форматов (например, Basis Universal) или настроить динамический выбор текстур в зависимости от типа устройства. Попробуйте интегрировать эту систему в свой проект и измерьте прирост производительности на мобильных устройствах.