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

Вы когда-нибудь сталкивались с ситуацией, когда для самого предзагрузчика нужны ресурсы, например, логотип или конфигурационный файл? Обычный `preload()` здесь не поможет, так как он вызывается уже после инициализации сцены. Phaser предлагает элегантное решение: загрузку файлов через payload в конфигурации сцены. Этот метод позволяет загрузить критически важные ресурсы ещё до вызова `Scene.preload()`, что идеально подходит для прелоадеров, конфигов или базовых UI-элементов, необходимых для самого процесса загрузки.

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

Живой запуск

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

Исходный код


//  Files specified in the Scene config files payload
//  will be loaded in *before* the Scene is started,
//  meaning they're available before even the Scene.preload function (if set) is called

//  This is perfect for loading in small JSON config files for example,
//  or a tiny amount of preloader assets that the preloader itself needs to use.
class Example extends Phaser.Scene
{
    constructor ()
    {
        super({
            pack: {
                files: [
                    { type: 'image', key: 'sonic', url: 'assets/sprites/sonic_havok_sanity.png' }
                ]
            }
        });
    }

    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        //  You can still preload other assets too
        this.load.image('face', 'assets/pics/bw-face.png');
    }

    create ()
    {
        this.add.image(0, 0, 'face').setOrigin(0);
        this.add.image(0, 0, 'sonic').setOrigin(0);
    }
}

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

const game = new Phaser.Game(gameConfig);

Что такое Payload и зачем он нужен?

В Phaser жизненный цикл сцены обычно начинается с метода preload(), где мы указываем, какие изображения, звуки или данные нужно загрузить. Но что, если для отображения экрана загрузки нужна картинка? Её-то и негде загрузить заранее.

Здесь на помощь приходит параметр pack в конструкторе сцены. Файлы, указанные в payload, загружаются движком на самом первом этапе, ещё до создания экземпляра сцены и вызова какого-либо из её стандартных методов (init, preload, create). Это гарантирует их стопроцентную доступность в момент старта сцены.

Основные сценарии использования: * Загрузка ассетов для кастомного прелоадера (спиннер, фон, логотип). * Подгрузка небольших JSON-файлов с конфигурацией игры или уровня. * Предварительная загрузка критичных шрифтов или UI-китов.

Как объявить Payload в сцене

Payload задаётся прямо в вызове родительского конструктора super(). Внутри объекта конфигурации сцены нужно определить свойство pack, которое содержит массив files.

Давайте разберём пример из исходного кода. В конструкторе класса сцены Example мы передаём объект с pack:

constructor ()
{
    super({
        pack: {
            files: [
                { type: 'image', key: 'sonic', url: 'assets/sprites/sonic_havok_sanity.png' }
            ]
        }
    });
}

Каждый элемент массива files — это объект с тремя обязательными полями: * type: тип загружаемого ресурса ('image', 'json', 'audio' и т.д.). * key: строковый идентификатор, по которому вы будете обращаться к ресурсу в коде. * url: путь к файлу.

В этом примере изображение с ключом 'sonic' будет загружено в кеш Phaser до любого другого действия в сцене.

Использование загруженных ассетов и обычный preload

Ассеты из payload становятся доступными так же, как и загруженные стандартным способом. Их можно использовать в любом методе сцены, включая create(). Обратите внимание, что в методе create() нашего примера спрайт 'sonic' добавляется на сцену без каких-либо проверок на загрузку — мы уверены, что он уже готов.

create ()
{
    this.add.image(0, 0, 'face').setOrigin(0);
    this.add.image(0, 0, 'sonic').setOrigin(0);
}

Важно понимать, что payload не заменяет стандартный preload(). Это дополнительный, более ранний этап загрузки. В том же примере в методе preload() загружается второе изображение ('face') обычным способом, через this.load.image. Это демонстрирует гибридный подход.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.load.image('face', 'assets/pics/bw-face.png');
}

Сначала загрузится 'sonic' (из payload), затем Phaser вызовет preload() и начнёт загрузку 'face'. Оба изображения появятся на сцене в create().

Практические рекомендации и частые ошибки

1. **Только для небольших файлов**: Payload идеален для нескольких лёгких файлов. Не используйте его для загрузки всего контента игры, это заблокирует старт сцены. Основную массу ассетов грузите в preload(). 2. **Относительные пути**: URL в payload указываются относительно базового пути игры или абсолютно. Если вы позже меняете this.load.setBaseURL() в preload(), это не повлияет на пути, указанные в payload. 3. **Проверка ключей**: Убедитесь, что ключи (key) для ресурсов из payload не конфликтуют с ключами из preload(). Phaser перезапишет ресурс в кеше, если ключи совпадут. 4. **Для JSON**: Этот метод отлично подходит для загрузки конфигов. Загруженный JSON будет автоматически разобран и доступен в кеше по указанному ключу.

// Пример загрузки JSON-конфига через payload
files: [
    { type: 'json', key: 'levelConfig', url: 'data/level1.json' }
]

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

Payload в конфигурации сцены — это мощный, но часто упускаемый из виду инструмент в Phaser. Он решает конкретную проблему загрузки ресурсов «нулевого» уровня, которые должны быть доступны до начала стандартного цикла. Попробуйте использовать его для создания кастомного анимированного прелоадера, который сам требует графики, или для мгновенной загрузки основных настроек игры. Экспериментируйте с загрузкой разных типов файлов (например, 'atlas' или 'audio') через payload, чтобы понять, как это влияет на стартовое время вашей игры.