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

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

Версия 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(
            {
                "key": "labs",
                "url": {
                    '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, 'labs', 'bubble256').setOrigin(0);
        const logo = this.add.sprite(80, 100, 'labs', '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);

Настройка базового URL и загрузка текстур

Первым шагом является настройка базового пути для всех ресурсов и загрузка самой текстуры с помощью метода load.texture. Этот метод принимает объект конфигурации, который описывает различные форматы сжатия и путь к несжатому атласу.

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

this.load.texture(
    {
        "key": "labs",
        "url": {
            '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` }
        }
    }
);

Здесь key — это уникальный идентификатор, под которым текстура будет доступна в коде (например, 'labs'). Объект url содержит ключи для разных алгоритмов сжатия. Phaser автоматически проверит, какой из форматов поддерживается браузером или устройством, и загрузит подходящий. Формат IMG служит резервным вариантом — обычным PNG-изображением. Важно, что для всех вариантов используется один и тот же файл атласа (textures.json), который описывает расположение отдельных кадров (спрайтов) на текстуре.

Создание спрайтов и доступ к свойствам текстуры

После загрузки текстуры в методе create мы можем создавать спрайты, используя загруженный атлас. Каждый спрайт создаётся с указанием ключа текстуры и имени кадра из атласа.

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

Метод this.add.sprite принимает координаты X, Y, ключ текстуры и имя кадра. setOrigin(0) устанавливает точку отсчёта (origin) спрайта в его левый верхний угол, что удобно для позиционирования. Ключ 'labs' ссылается на загруженную текстуру, а 'bubble256' и 'logo' — это имена кадров, определённые в JSON-атласе.

После создания спрайта мы можем получить информацию о загруженном формате сжатия через свойство frame.source.compressionAlgorithm.

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

Здесь создаётся текстовый объект, который отображает строку с названием алгоритма сжатия (например, 'ASTC'), использованного для текстуры этого спрайта. setOrigin(0.5, 0) центрирует текст по горизонтали относительно точки (400, 570). Это полезно для отладки и демонстрации того, какой формат был выбран движком.

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

Для запуска примера необходимо создать стандартную конфигурацию игры Phaser и передать в неё нашу сцену Demo.

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

const game = new Phaser.Game(config);

Конфигурация задаёт базовые параметры: type определяет рендерер (WebGL или Canvas), parent — ID HTML-элемента для встраивания канваса, width и height — размеры игрового поля. backgroundColor устанавливает фоновый цвет. Ключевой параметр scene указывает класс сцены, которая будет запущена первой. Создание экземпляра Phaser.Game с этой конфигурацией инициирует весь процесс загрузки и отрисовки.

Как работает выбор формата сжатия

Phaser 3 внутренне проверяет поддержку различных форматов сжатия текстур браузером и графическим API (WebGL). При вызове load.texture с конфигурацией, содержащей несколько форматов, движок проходит по списку в порядке, определённом в объекте (ASTC, ETC, PVRTC, S3TC, IMG), и загружает первый поддерживаемый.

Это поведение критически важно для кроссплатформенной разработки. Например, ASTC эффективен на современных мобильных устройствах с Android, PVRTC — на iOS, а S3TC (BC3) широко поддерживается десктопными браузерами. Формат IMG (обычное PNG) выступает универсальным фолбэком для сред, где аппаратное сжатие текстур недоступно.

Такой подход позволяет разработчику подготовить один набор ассетов в нескольких форматах и не беспокоиться о ручной проверке возможностей устройства — Phaser сделает это автоматически, обеспечив наилучшую производительность.

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

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

  1. Добавить свои текстуры, сжатые разными алгоритмами, и проверить их отображение на различных устройствах
  2. Реализовать кастомную логику выбора формата на основе пользовательских данных
  3. Использовать этот подход для загрузки анимаций, где каждый кадр — часть одного атласа