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

Оптимизация графики критически важна для производительности игр, особенно на мобильных устройствах. Phaser предлагает элегантное решение — автоматический выбор наиболее подходящего сжатого формата текстур из нескольких предоставленных вариантов. Это позволяет разработчику подготовить текстурные атласы во всех популярных форматах (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/');
        this.load.texture(
            {
                "key": "labs",
                "url": {
                    "ASTC": "assets/compressed/labs-ASTC-4x4-lRGB.pvr",
                    "ETC": "assets/compressed/labs-ETC2-lRGB.pvr",
                    "PVRTC": "assets/compressed/labs-PVRTC-4BPP-lRGB.pvr",
                    "S3TC": "assets/compressed/labs-S3TC-BC3-lRGB.pvr",
                    "IMG": "assets/compressed/uncompressed/labs.png"
                }
            }
        );
    }

    create ()
    {
        const logo = this.add.image(400, 300, 'labs');

        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);

Проблема: множество форматов сжатия текстур

Разные браузеры и графические API поддерживают разные форматы сжатия текстур. Например, Safari на iOS хорошо работает с PVRTC, Chrome на Android предпочитает ETC2 или ASTC, а десктопные браузеры часто поддерживают S3TC (BC).

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

Решение: метод `load.texture()` с конфигурационным объектом

Вместо стандартного this.load.image() Phaser предоставляет мощный метод load.texture(). Он принимает объект конфигурации, в котором можно указать одну текстуру, но несколько путей к ее файлам в разных форматах сжатия.

Движок анализирует окружение и загружает только один, наиболее подходящий файл. В исходном коде примера это выглядит так:

this.load.texture(
    {
        "key": "labs",
        "url": {
            "ASTC": "assets/compressed/labs-ASTC-4x4-lRGB.pvr",
            "ETC": "assets/compressed/labs-ETC2-lRGB.pvr",
            "PVRTC": "assets/compressed/labs-PVRTC-4BPP-lRGB.pvr",
            "S3TC": "assets/compressed/labs-S3TC-BC3-lRGB.pvr",
            "IMG": "assets/compressed/uncompressed/labs.png"
        }
    }
);

**Ключевые моменты:** * key: строковый идентификатор, под которым текстура будет доступна в кеше (например, 'labs'). * url: объект, где ключи — это имена форматов, а значения — пути к файлам. Формат IMG используется как резервный, если ни один сжатый формат не поддерживается. * Порядок ключей в объекте url не имеет значения. Phaser сам определяет приоритетность на основе возможностей системы.

Использование и проверка загруженного формата

После загрузки текстура используется точно так же, как и любая другая, через ее key. В примере создается спрайт стандартным методом this.add.image().

const logo = this.add.image(400, 300, 'labs');

Любопытная деталь: Phaser сохраняет информацию о том, какой именно формат был загружен. Эту метаинформацию можно получить из объекта frame текстуры. В примере она выводится на экран:

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

Свойство logo.frame.source.compressionAlgorithm будет содержать строку с названием использованного алгоритма (например, 'PVRTC'), что полезно для отладки и логирования.

Практические шаги по подготовке ассетов

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

1. **Создайте исходное изображение** в высоком качестве (PNG). 2. **Конвертируйте его** в несколько целевых форматов сжатия. Для этого можно использовать инструменты вроде: * **Texture Packer** (платный, с поддержкой Phaser). * **PVRTexTool** от Imagination Technologies (бесплатный). * **ASTC Encoder** от ARM. * **Crunch** (для формата CRN, который конвертируется в S3TC). 3. **Поместите все получившиеся файлы** (.pvr, .ktx, .dds, .png) в папку с ассетами вашего проекта. 4. **Скорректируйте пути** в конфигурационном объекте url под структуру вашего проекта.

Важно: Phaser по умолчанию не включает все декодеры. Для поддержки форматов вроде PVR или S3TC может потребоваться подключение дополнительных плагинов, таких как Phaser.Textures.PVRParser.

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

Использование load.texture() с набором сжатых текстур — это профессиональный подход к управлению графическими ресурсами. Он обеспечивает максимальную производительность на каждой платформе без необходимости писать сложную логику определения возможностей устройства. **Идеи для экспериментов:** * Сравните размеры бандла и скорость загрузки, используя только PNG и набор сжатых текстур. * Попробуйте добавить в объект url форматы BASIS или CRN для еще большей оптимизации. * Создайте систему логирования, которая при запуске игры выводит в консоль список всех загруженных текстур и использованные для них алгоритмы сжатия, чтобы анализировать охват ваших ассетов на разных устройствах.