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

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

Версия 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', textureURL: `${path}/compressed/textures-ASTC-4x4-lRGB.pvr`, atlasURL: `${path}/uncompressed/textures.json` },
            'ETC': { type: 'PVR', textureURL: `${path}/compressed/textures-ETC2-lRGB.pvr`, atlasURL: `${path}/uncompressed/textures.json` },
            'PVRTC': { type: 'PVR', textureURL: `${path}/compressed/textures-PVRTC-4BPP-lRGB.pvr`, atlasURL: `${path}/uncompressed/textures.json` },
            'S3TC': { type: 'PVR', textureURL: `${path}/compressed/textures-S3TC-BC3-lRGB.pvr`, atlasURL: `${path}/uncompressed/textures.json` },
            'IMG': { textureURL: `${path}/textures.png`, atlasURL: `${path}/uncompressed/textures.json` }
        });
    }

    create ()
    {
        const bubble = this.add.sprite(0, 40, 'test', 'bubble256').setOrigin(0);
        const logo = this.add.sprite(80, 100, 'test', 'logo').setOrigin(0);

        // this.add.text(400, 570, logo.frame.source.compressionAlgorithm).setOrigin(0.5, 0);
    }
}

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

const game = new Phaser.Game(config);

Что такое сжатые текстуры и зачем они нужны

Сжатые текстуры — это изображения, обработанные специальными алгоритмами (ASTC, ETC, PVRTC, S3TC) для уменьшения занимаемого места на диске и в оперативной памяти. В отличие от сжатия форматами вроде PNG или JPEG, которое распаковывается в ОЗУ в полном объеме, аппаратно-ускоренное сжатие текстур (GPU texture compression) остается в сжатом виде и в видеопамяти. Это экономит трафик, ускоряет загрузку и позволяет хранить больше детализированных ассетов.

Phaser может загружать несколько вариантов одного и того же атласа, сжатого разными алгоритмами, и автоматически выбрать тот, который поддерживается браузером и видеокартой пользователя. Это называется feature detection.

Структура метода `load.texture`

Ключевой метод для загрузки сжатых атласов — this.load.texture. Он принимает два параметра: ключ (key) для последующего использования и объект конфигурации. Внутри этого объекта для каждого формата сжатия указывается путь к файлу текстуры (.pvr) и путь к файлу атласа (.json). Последний элемент 'IMG' — это fallback-вариант в обычном PNG, который будет использован, если браузер не поддерживает ни один из аппаратных форматов.

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

Обратите внимание на параметр type: 'PVR'. Он указывает Loader, что файл текстуры имеет формат PVR, который является контейнером для сжатых данных. Пути задаются через шаблонные строки, что делает код гибким.

Создание спрайтов из загруженного атласа

После успешной загрузки в методе create() мы можем создавать спрайты, используя загруженный атлас. Ключ 'test', который был указан при загрузке, теперь используется как текстура (первый аргумент this.add.sprite). Четвертый аргумент — это имя фрейма внутри атласа, которое соответствует записи в JSON-файле атласа.

const bubble = this.add.sprite(0, 40, 'test', 'bubble256').setOrigin(0);
const logo = this.add.sprite(80, 100, 'test', 'logo').setOrigin(0);

Метод .setOrigin(0) устанавливает точку вращения и выравнивания спрайта в его левый верхний угол. Это удобно для точного позиционирования. Phaser автоматически использует ту версию текстуры (сжатую или PNG), которая была загружена, поэтому дальнейшая работа с фреймами ничем не отличается от работы с обычным атласом.

Как узнать, какой алгоритм сжатия был выбран

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

// this.add.text(400, 570, logo.frame.source.compressionAlgorithm).setOrigin(0.5, 0);

Свойство logo.frame.source.compressionAlgorithm будет содержать строку с именем алгоритма (например, 'ASTC') или undefined, если был загружен fallback-формат (PNG). Раскомментировав эту строку, вы сможете вывести эту информацию на экран.

Подготовка сжатых текстур для проекта

Чтобы использовать этот подход, вам потребуются сжатые текстуры в формате .pvr и JSON-атлас. Атлас должен быть одинаковым для всех вариантов текстур — меняется только само изображение-текстура. Для создания таких файлов можно использовать инструменты вроде: * Texture Packer (с поддержкой экспорта в несколько форматов сжатия). * PVRTexTool от Imagination Technologies. * Конвертеры, такие как etcpack или astcenc.

Важно: поместите сжатые .pvr файлы и PNG-fallback в папку, указанную в textureURL, а JSON-атлас — в папку, указанную в atlasURL. В примере пути разделены, что демонстрирует гибкость подхода.

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

Использование сжатых текстурных атласов в Phaser — это профессиональный подход к оптимизации веб-игры. Он снижает требования к трафику и ускоряет загрузку, особенно на мобильных устройствах. Для экспериментов попробуйте

  1. Создать свой атлас и сжать его разными алгоритмами, сравнив размеры файлов
  2. Добавить больше форматов (например, Basis Universal)
  3. Реализовать логику, которая принудительно выбирает определенный формат для тестирования, используя свойства frame.source. Это мощный инструмент в арсенале разработчика, стремящегося к максимальной производительности