Прогресс загрузки и отслеживание событий

В приложениях на PixiJS значительная часть работы связана с загрузкой внешних ресурсов: изображений, спрайтшитов, шрифтов, JSON-файлов, видео и аудио. Корректная организация процесса загрузки напрямую влияет на стабильность, производительность и пользовательский опыт.

В современных версиях библиотеки используется модуль загрузки из пакета @pixi/assets. Он предоставляет:

  • централизованную систему управления ресурсами;
  • отслеживание прогресса;
  • события завершения и ошибок;
  • кэширование;
  • возможность параллельной загрузки.

Основной объект для работы — Assets.


Базовая загрузка ресурсов

Простейший пример загрузки одного ресурса:

import { Assets } from 'pixi.js';

const texture = await Assets.load('images/player.png');

При вызове Assets.load():

  1. Проверяется кэш.
  2. Если ресурс отсутствует, начинается асинхронная загрузка.
  3. После завершения возвращается готовый объект (например, Texture).

Однако при загрузке нескольких ресурсов требуется механизм отслеживания прогресса и управления очередью.


Загрузка набора ресурсов (Batch Loading)

Для загрузки нескольких файлов используется массив:

await Assets.load([
  'images/bg.png',
  'images/player.png',
  'images/enemy.png'
]);

PixiJS выполняет параллельную загрузку, оптимизируя количество одновременных запросов.

Чтобы контролировать процесс более гибко, используется Bundle.


Bundles: группировка ресурсов

Bundles позволяют логически объединить ресурсы:

Assets.addBundle('level1', {
  background: 'images/bg.png',
  player: 'images/player.png',
  enemy: 'images/enemy.png'
});

await Assets.loadBundle('level1');

После загрузки доступ к ресурсам осуществляется по ключам:

const playerTexture = Assets.get('player');

Преимущества bundle-подхода:

  • структурированность;
  • удобное управление сценами;
  • возможность выгрузки неиспользуемых ресурсов.

Отслеживание прогресса загрузки

Для отображения прогресса используется специальный callback.

Пример с прогресс-обработчиком

await Assets.load(
  ['images/bg.png', 'images/player.png'],
  (progress) => {
    console.log(`Прогресс: ${Math.round(progress * 100)}%`);
  }
);

Параметр progress:

  • значение от 0 до 1;
  • отражает долю завершённой загрузки.

Это позволяет реализовать:

  • прогресс-бары;
  • анимации загрузки;
  • динамическое обновление UI.

Реализация графического индикатора прогресса

Пример использования Graphics для создания прогресс-бара:

import { Application, Graphics } from 'pixi.js';

const app = new Application();
document.body.appendChild(app.view);

const progressBar = new Graphics();
app.stage.addChild(progressBar);

function drawProgress(value) {
  progressBar.clear();
  progressBar.beginFill(0x00ff00);
  progressBar.drawRect(100, 300, 400 * value, 20);
  progressBar.endFill();
}

await Assets.load(
  ['images/bg.png', 'images/player.png'],
  (progress) => {
    drawProgress(progress);
  }
);

В данном примере:

  • value изменяется от 0 до 1;
  • ширина прямоугольника масштабируется пропорционально прогрессу;
  • вызов clear() предотвращает наложение графики.

События загрузки

PixiJS построен на асинхронной модели с использованием Promises. Однако логика событийной обработки остаётся актуальной.

Основные этапы загрузки

  1. Инициализация запроса.
  2. Начало загрузки.
  3. Получение данных.
  4. Парсинг (если требуется).
  5. Кэширование.
  6. Завершение.

В старых версиях PixiJS использовался Loader с событийной моделью (onProgress, onComplete, onError). В современных версиях предпочтение отдаётся Promise-подходу.


Обработка ошибок

Ошибка загрузки может возникнуть по причинам:

  • неправильный путь;
  • отсутствие файла на сервере;
  • CORS-ограничения;
  • сетевые проблемы.

Обработка осуществляется через try/catch:

try {
  await Assets.load('images/missing.png');
} catch (error) {
  console.error('Ошибка загрузки:', error);
}

При массовой загрузке:

try {
  await Assets.load(['a.png', 'b.png']);
} catch (error) {
  // обработка
}

Если хотя бы один ресурс не загрузился, Promise отклоняется.


Отслеживание прогресса при загрузке Bundle

await Assets.loadBundle('level1', (progress) => {
  console.log(progress);
});

Принцип идентичен load(), но применяется ко всей группе.


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

Для оптимизации памяти используется отложенная загрузка:

  • сначала загружается минимальный набор (меню, UI);
  • затем ресурсы конкретного уровня.

Пример:

await Assets.loadBundle('menu');
startMenu();

await Assets.loadBundle('level1');
startLevel();

Такой подход:

  • сокращает первоначальное время ожидания;
  • уменьшает пиковое потребление памяти;
  • ускоряет старт приложения.

Выгрузка ресурсов

Отслеживание жизненного цикла ресурсов важно при работе с большими проектами.

Assets.unloadBundle('level1');

После вызова:

  • текстуры удаляются из кэша;
  • GPU-память освобождается;
  • повторная загрузка потребует нового запроса.

Также можно удалить конкретный ресурс:

Assets.unload('images/player.png');

Кэширование и повторная загрузка

PixiJS автоматически кэширует ресурсы. Повторный вызов:

await Assets.load('images/player.png');

не выполняет новый сетевой запрос, если ресурс уже находится в кэше.

Получение из кэша:

const texture = Assets.get('images/player.png');

Это важно при работе с прогрессом: уже загруженные файлы не влияют на текущий процент.


Управление параллельностью загрузки

PixiJS внутренне ограничивает количество одновременных HTTP-запросов. Это предотвращает:

  • перегрузку сети;
  • блокировку браузера;
  • превышение лимитов соединений.

При необходимости возможна настройка через конфигурацию:

Assets.init({
  concurrency: 5
});

concurrency определяет максимальное число параллельных загрузок.


Интеграция с игровой сценой

Часто загрузка организуется в виде отдельной сцены:

  1. Создаётся сцена LoadingScene.
  2. Отображается индикатор прогресса.
  3. Выполняется Assets.loadBundle.
  4. После завершения сцена переключается.

Пример логики:

class LoadingScene {
  async load() {
    await Assets.loadBundle('level1', (progress) => {
      this.updateProgress(progress);
    });
    this.onComplete();
  }
}

Преимущества:

  • разделение ответственности;
  • чистая архитектура;
  • возможность повторного использования.

События текстур и BaseTexture

После загрузки текстуры создаётся BaseTexture. Внутренне она также генерирует события:

  • loaded
  • error
  • dispose

Хотя в большинстве случаев работа идёт через Assets, понимание этого механизма важно при создании кастомных загрузчиков.


Работа со спрайтшитами

При загрузке JSON-спрайтшита:

await Assets.load('spritesheet.json');

PixiJS:

  1. Загружает JSON.
  2. Анализирует пути к изображениям.
  3. Загружает текстурный атлас.
  4. Разбивает его на кадры.

Прогресс учитывает все связанные файлы.


Предзагрузка (Preloading)

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

Assets.backgroundLoadBundle('level2');

Метод запускает фоновую загрузку без блокировки текущей логики. Это позволяет:

  • загружать следующий уровень во время игры;
  • минимизировать паузы между сценами.

Комбинирование Promise и событий

Пример с ручным управлением:

const promise = Assets.loadBundle('level1', (progress) => {
  console.log(progress);
});

promise.then(() => {
  console.log('Готово');
}).catch((err) => {
  console.error(err);
});

Такой подход позволяет интегрировать загрузку в существующую архитектуру на основе Promise.


Производительность и оптимизация

При работе с прогрессом и событиями необходимо учитывать:

  • крупные текстуры увеличивают время декодирования;
  • JSON-файлы спрайтшитов добавляют этап парсинга;
  • количество HTTP-запросов влияет на общий процент.

Рекомендуется:

  • объединять изображения в атласы;
  • использовать WebP или AVIF;
  • минимизировать число мелких файлов;
  • применять ленивую загрузку.

Практическая схема полной загрузки

  1. Инициализация Assets.
  2. Регистрация bundle.
  3. Отображение сцены загрузки.
  4. Запуск loadBundle с callback прогресса.
  5. Обработка ошибок.
  6. Переход к основной сцене.
  7. Выгрузка ненужных ресурсов.

Такая архитектура обеспечивает:

  • прозрачный контроль над процессом;
  • масштабируемость проекта;
  • устойчивость к сетевым сбоям;
  • эффективное управление памятью.

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