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

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

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

Живой запуск

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

Исходный код


class Example extends Phaser.Scene {
    preload() {
        
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
    }

    create() {
        const gl = this.game.context;
        const renderer = this.game.renderer;

        var contextLost = function (event) 
        {
            console.log('custom context lost event here');
        };

        renderer.setContextHandlers(contextLost)

        const sprite = this.add.sprite(400, 300, 'eye').setInteractive();

        sprite.on('pointerdown', function (pointer) {
            gl.getExtension("WEBGL_lose_context").loseContext();
        });
    }
}

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

const game = new Phaser.Game(config);

Что такое потеря контекста WebGL и почему это важно

WebGL контекст — это низкоуровневый доступ к графическому API браузера. Его потеря означает, что GPU больше не может отрисовывать кадры для вашей игры. Phaser автоматически пытается восстановить контекст и перезапустить рендерер, но все текстуры, шейдеры и буферы, созданные до потери, становятся недействительными.

Кастомный обработчик позволяет вам перехватить этот момент и выполнить дополнительную логику: сбросить состояние, уведомить игрока или перезагрузить только те ресурсы, которые не будут восстановлены автоматически (например, кастомные данные в текстурах).

Инициализация сцены и загрузка ресурсов

В примере создается стандартная сцена Phaser. В методе preload загружается одно изображение. Ключевой момент — используется this.load.setBaseURL, чтобы указать базовый путь для загрузки ассетов.

class Example extends Phaser.Scene {
    preload() {
        this.load.setBaseURL('https://raw.githubusercontent.com/phaserjs/examples/master/public/');
        this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
    }

Получение доступа к рендереру и WebGL контексту

В методе create мы получаем прямой доступ к объекту WebGL rendering context через this.game.context и к рендереру Phaser через this.game.renderer. Эти объекты нужны для подписки на событие и его принудительной генерации в демо-целях.

create() {
    const gl = this.game.context;
    const renderer = this.game.renderer;

Создание и установка кастомного обработчика

Здесь определяется функция-обработчик contextLost. В данном примере она просто логирует сообщение в консоль. На практике здесь можно вызвать метод для показа экрана "Игра приостановлена" или запустить процедуру мягкого перезапуска графической подсистемы.

Метод renderer.setContextHandlers регистрирует эту функцию для события потери контекста. Важно: это добавляет, а не заменяет встроенную обработку Phaser.

var contextLost = function (event) 
{
    console.log('custom context lost event here');
};

renderer.setContextHandlers(contextLost)

Симуляция потери контекста для тестирования

Чтобы протестировать обработчик без реального сбоя, пример создает спрайт и при клике по нему вызывает специальное расширение WEBGL_lose_context, которое позволяет симулировать потерю контекста программно. Это исключительно отладочная функциональность, недоступная в продакшене.

const sprite = this.add.sprite(400, 300, 'eye').setInteractive();

sprite.on('pointerdown', function (pointer) {
    gl.getExtension("WEBGL_lose_context").loseContext();
});

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

Конфигурация игры явно указывает на использование Phaser.WEBGL. Это обязательное условие, так как потеря контекста актуальна только для рендерера WebGL. Для Canvas рендерера этот пример не имеет смысла.

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

const game = new Phaser.Game(config);

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

Добавление кастомного обработчика потери контекста WebGL — это продвинутая техника повышения отказоустойчивости вашей игры. Она особенно полезна для проектов с тяжелой графикой, сложными шейдерами или при работе на слабых устройствах. Для экспериментов попробуйте

  1. В обработчике не только логировать, но и сохранять критичное состояние игры перед сбросом
  2. Восстанавливать кастомные Uniform-переменные в шейдерах после того, как Phaser пересоздаст контекст
  3. Связать эту систему с UI, чтобы показывать игроку понятное сообщение о временных проблемах с графикой