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

При загрузке тяжелых ресурсов, таких как аудиофайлы, важно показывать пользователю прогресс. Встроенный общий индикатор загрузки в Phaser удобен, но что, если вам нужен детальный контроль? Событие `fileprogress` позволяет создавать индивидуальные индикаторы прогресса для каждого файла, делая процесс загрузки прозрачным и визуально приятным. Эта статья покажет, как реализовать несколько параллельных индикаторов загрузки для аудиофайлов.

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene
{
    preload ()
    {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.add.image(400, 300, 'bear').setScale(2);

        const progress = this.add.graphics();
        
        progress.fillStyle(0xffffff);

        //  3 progress bars, one per file.

        this.load.on('fileprogress', (file, value) =>
        {

            // progress.clear();

            if (file.key === 'goldrunner')
            {
                progress.fillRect(400, 500 - (value * 400), 60, value * 400);
            }
            else if (file.key === 'heroquest')
            {
                progress.fillRect(510, 500 - (value * 400), 60, value * 400);
            }
            else if (file.key === 'goa')
            {
                progress.fillRect(620, 500 - (value * 400), 60, value * 400);
            }

        });

        this.load.audio('goldrunner', 'assets/audio/Scyphe-Goldrunner_(Maccie_Pimp_Me Up_Remix).mp3');
        this.load.audio('heroquest', 'assets/audio/Totta-HeroQuest-Pophousedub-remix.mp3');
        this.load.audio('goa', 'assets/audio/tommy_in_goa.mp3');
    }

    create ()
    {
        const music = this.sound.add('goa');

        music.play();
    }
}

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

const game = new Phaser.Game(config);

Настройка сцены и создание графики

В методе preload() сцены мы выполняем базовую настройку. Устанавливаем базовый URL для загрузчиков, добавляем фоновое изображение и, что самое важное, создаем графический объект progress. Этот объект типа Phaser.GameObjects.Graphics будет использоваться для отрисовки наших индикаторов. Мы сразу задаем ему цвет заливки.

preload ()
{
    this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
    this.add.image(400, 300, 'bear').setScale(2);

    const progress = this.add.graphics();
    progress.fillStyle(0xffffff);

Подписка на событие fileprogress

Ключевой элемент — подписка на событие 'fileprogress' загрузчика (this.load). Это событие срабатывает каждый раз, когда меняется прогресс загрузки одного конкретного файла. Обработчик события получает два параметра: объект file и значение value (число от 0 до 1).

this.load.on('fileprogress', (file, value) =>
{
    // progress.clear();

    if (file.key === 'goldrunner')
    {
        progress.fillRect(400, 500 - (value * 400), 60, value * 400);
    }
    else if (file.key === 'heroquest')
    {
        progress.fillRect(510, 500 - (value * 400), 60, value * 400);
    }
    else if (file.key === 'goa')
    {
        progress.fillRect(620, 500 - (value * 400), 60, value * 400);
    }
});

Внутри обработчика мы проверяем свойство file.key, чтобы понять, прогресс какого именно файла обновился. Для каждого ключа мы рисуем прямоугольник в своей позиции на экране. Вызов progress.clear() закомментирован, так как без него столбцы индикаторов будут расти, а с ним — каждый кадр перерисовываться заново.

Логика отрисовки индикаторов

Давайте разберем вызов progress.fillRect. Он рисует залитый прямоугольник.

progress.fillRect(400, 500 - (value * 400), 60, value * 400);

* 400 — координата X левого верхнего угла прямоугольника. * 500 - (value * 400) — координата Y. Поскольку система координат в Phaser начинается сверху, мы вычитаем текущую высоту (value * 400) из базовой линии (500). Это заставляет прямоугольник расти снизу вверх. * 60 — ширина прямоугольника. * value * 400 — высота прямоугольника. Когда value равен 0, высота 0. Когда value достигает 1, высота становится 400 пикселей. Таким образом, для каждого файла мы создаем отдельный столбец, который плавно заполняется по мере загрузки.

Инициирование загрузки аудиофайлов

После настройки обработчика события мы сообщаем загрузчику, какие файлы нужно загрузить, используя метод this.load.audio. Первый аргумент — это уникальный ключ (key), по которому мы идентифицировали файлы в обработчике события fileprogress.

this.load.audio('goldrunner', 'assets/audio/Scyphe-Goldrunner_(Maccie_Pimp_Me Up_Remix).mp3');
this.load.audio('heroquest', 'assets/audio/Totta-HeroQuest-Pophousedub-remix.mp3');
this.load.audio('goa', 'assets/audio/tommy_in_goa.mp3');

Как только эти строки выполняются, начинается загрузка, и наше событие fileprogress начинает генерироваться для каждого файла.

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

После завершения загрузки всех файлов (включая изображение 'bear') Phaser автоматически вызовет метод create() сцены. Здесь мы можем безопасно использовать загруженные аудиофайлы. В примере создается и запускается звуковой объект с ключом 'goa'.

create ()
{
    const music = this.sound.add('goa');
    music.play();
}

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

Событие fileprogress — мощный инструмент для создания кастомных интерфейсов загрузки в Phaser. Вы можете визуализировать прогресс для любого типа ресурсов: изображений, аудио, JSON-данных. Для экспериментов попробуйте: изменить форму индикаторов (например, на круговые), добавить текстовые подписи с процентами для каждого файла, реализовать общий прогресс-бар, суммирующий данные от всех файлов, или анимировать завершение загрузки каждого индикатора.