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

Загрузка картинок, звуков и атласов — рутинная, но критически важная часть разработки игры. Phaser предлагает несколько способов вызова методов загрузчика, от классических до объектно-ориентированных. В этой статье мы разберем, как использовать объектный синтаксис метода `load.image()`, который дает больше контроля над процессом, позволяет тонко настраивать XHR-запросы и делает код чище при загрузке нескольких файлов. Это полезно для организации сложных сцен загрузки и работы с защищенными ресурсами.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        //  Load via an object
        // this.load.image({ key: 'bunny', url: 'assets/sprites/bunny.png' });

        //  Load via an array of objects
        /*
        this.load.image([
            { key: 'bunny', url: 'assets/sprites/bunny.png' },
            { key: 'atari', url: 'assets/sprites/atari400.png' },
            { key: 'logo', url: 'assets/sprites/phaser2.png' }
        ]);
        */

        //  Object based including XHR Settings

        this.load.image({
            key: 'bunny',
            url: 'assets/sprites/bunny.png',
            xhr: {
                user: 'root',
                password: 'th3G1bs0n',
                timeout: 10,
                header: 'Content-Type',
                headerValue: 'image/png'
            }
        });

        /*
        //  Auto-filename based on key:

        //  Will load bunny.png from the defined path, because '.png' is the default extension.
        this.load.image({ key: 'bunny' });

        //  Will load bunny.jpg from the defined path, because of the 'ext' property.
        this.load.image({ key: 'bunny', extension: 'jpg' });

        //  ----------------------
        //  Texture Atlas Examples
        //  ----------------------

        //  Original atlas loader signature:
        //  this.load.atlas(key, textureURL, atlasURL, textureXhrSettings, atlasXhrSettings)

        this.load.atlas('level1', 'assets/level1/items.png', 'assets/level1/items.json');

        //  Object based
        this.load.atlas({ key: 'level1', textureURL: 'assets/level1/items.png', atlasURL: 'assets/level1/items.json' });
        */
    }

    create ()
    {
        this.add.image(400, 300, 'bunny');
    }
}

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

const game = new Phaser.Game(config);

Классический vs. объектный синтаксис

Традиционный способ загрузки изображения в Phaser хорошо знаком: передать ключ и URL строковыми аргументами. Однако API загрузчика поддерживает и альтернативный, объектный синтаксис.

Классический вызов выглядит так:

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

Его объектный аналог принимает один аргумент — объект конфигурации:

this.load.image({ key: 'bunny', url: 'assets/sprites/bunny.png' });

На первый взгляд, разница невелика. Однако объектный подход раскрывает свой потенциал, когда нужно передать дополнительные параметры, такие как настройки XHR, или загрузить несколько ресурсов одним вызовом через массив объектов.

Загрузка с настройкой XHR-запроса

Главное преимущество объектного синтаксиса — возможность детальной настройки HTTP-запроса через свойство xhr. Это бывает необходимо для доступа к ресурсам, защищенным базовой аутентификацией (Basic Auth), или для установки специфичных заголовков и таймаутов.

В примере из исходника показана загрузка спрайта с передачей учетных данных и заголовка:

this.load.image({
    key: 'bunny',
    url: 'assets/sprites/bunny.png',
    xhr: {
        user: 'root',
        password: 'th3G1bs0n',
        timeout: 10,
        header: 'Content-Type',
        headerValue: 'image/png'
    }
});

Здесь внутри свойства xhr задаются: - user и password для HTTP-аутентификации. - timeout для ограничения времени запроса (в данном случае всего 10 мс, что маловероятно для реального использования). - header и headerValue для установки произвольного HTTP-заголовка (в примере явно указывается MIME-тип).

Без объектного синтаксиса передать эти параметры в load.image() было бы невозможно.

Массовая загрузка и умные умолчания

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

Пример из закомментированного кода:

this.load.image([
    { key: 'bunny', url: 'assets/sprites/bunny.png' },
    { key: 'atari', url: 'assets/sprites/atari400.png' },
    { key: 'logo', url: 'assets/sprites/phaser2.png' }
]);

Такой подход делает код в preload() более структурированным, особенно когда ресурсов много.

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

// Загрузит <baseURL>/bunny.png
this.load.image({ key: 'bunny' });

// Загрузит <baseURL>/bunny.jpg, т.к. расширение переопределено
this.load.image({ key: 'bunny', extension: 'jpg' });

Это работает, если вы предварительно установили базовый путь через this.load.setBaseURL(), как сделано в примере. Такой подход стандартизирует именование файлов в проекте.

Применение к другим типам ресурсов

Объектный синтаксис — не эксклюзив для load.image(). Он поддерживается и другими методами загрузчика. Например, для загрузки атласа текстур (atlas) традиционный способ требует нескольких аргументов:

this.load.atlas('level1', 'assets/level1/items.png', 'assets/level1/items.json');

Его можно переписать в объектном стиле, что повышает читаемость, особенно при наличии XHR-настроек:

this.load.atlas({ 
    key: 'level1', 
    textureURL: 'assets/level1/items.png', 
    atlasURL: 'assets/level1/items.json' 
});

Аналогичный принцип, вероятно, применим к load.audio, load.bitmapFont и другим методам, где важна конфигурация. Всегда проверяйте актуальную документацию Phaser для подтверждения.

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

Объектный синтаксис методов загрузчика в Phaser — это мощный инструмент для написания чистого, гибкого и надежного кода. Он незаменим при работе с защищенными ресурсами, массовой загрузке и желании придерживаться консистентного стиля. **Идеи для экспериментов:** 1. Создайте систему, которая динамически формирует массив объектов для load.image() на основе JSON-манифеста ресурсов уровня. 2. Попробуйте загрузить аудиофайл с кастомным заголовком Authorization через свойство xhr. 3. Реализуйте «умный» загрузчик, который подставляет расширение файла (extension) на основе ключа, если файл с расширением по умолчанию не найден (используя событие LOAD_ERROR).