О чем этот пример
При разработке браузерных игр на WebGL вы можете столкнуться с ситуацией, когда графический контекст теряется. Это может произойти из-за переключения вкладок, системных уведомлений или проблем с драйверами. Phaser предоставляет механизм для регистрации обработчиков таких событий, что позволяет корректно восстановить состояние рендерера и избежать "чёрного экрана". В этой статье мы разберём, как использовать `setContextHandlers` для добавления кастомной логики при восстановлении контекста.
Версия 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 contextRestored = function (event)
{
console.log('custom context restored event here');
};
renderer.setContextHandlers(undefined, contextRestored)
const sprite = this.add.sprite(400, 300, 'eye').setInteractive();
sprite.on('pointerdown', function (pointer) {
gl.getExtension("WEBGL_lose_context").restoreContext();
});
}
}
const config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: Example
};
const game = new Phaser.Game(config);
Проблема потери WebGL-контекста
WebGL-контекст в браузере — это хрупкий ресурс. Операционная система или сам браузер могут его "отобрать" в любой момент, например, чтобы освободить память, когда вкладка неактивна. Если игра не обрабатывает это событие, после возвращения пользователь может увидеть лишь статичное или чёрное изображение.
Phaser внутренне обрабатывает стандартные сценарии восстановления, перезагружая текстуры и шейдеры. Однако иногда вам может потребоваться выполнить дополнительную, специфичную для игры логику: пересчитать данные, отправить аналитику или вывести сообщение в лог. Именно для этого существует метод setContextHandlers рендерера.
Метод `renderer.setContextHandlers`
Метод setContextHandlers позволяет переопределить обработчики событий webglcontextlost и webglcontextrestored. В нашем примере мы заменяем только обработчик восстановления.
Сначала мы получаем доступ к рендереру игры и WebGL-контексту. Затем объявляем функцию, которая будет вызвана при восстановлении контекста.
const gl = this.game.context;
const renderer = this.game.renderer;
var contextRestored = function (event)
{
console.log('custom context restored event here');
};
renderer.setContextHandlers(undefined, contextRestored)
Первый аргумент метода (undefined) — это обработчик для события потери контекста. Мы оставляем его пустым, чтобы использовать стандартную реализацию Phaser. Второй аргумент — наша кастомная функция contextRestored. Теперь при каждом восстановлении WebGL-контекста в консоли будет появляться наше сообщение.
Имитация события для тестирования
В обычных условиях ждать, пока система сама снимет контекст, неудобно. Для отладки можно принудительно инициировать это событие с помощью расширения WEBGL_lose_context. Оно является частью спецификации WebGL и предназначено специально для тестирования.
В примере мы создаём интерактивный спрайт. По клику на него мы получаем расширение из контекста и вызываем метод restoreContext, который симулирует восстановление.
const sprite = this.add.sprite(400, 300, 'eye').setInteractive();
sprite.on('pointerdown', function (pointer) {
gl.getExtension("WEBGL_lose_context").restoreContext();
});
Этот подход позволяет быстро проверить, срабатывает ли ваш обработчик, без необходимости воспроизводить реальные условия потери контекста.
Практическое применение и важные замечания
В реальном проекте в обработчике contextRestored вы можете:
1. **Переинициализировать кастомные шейдеры:** Если вы используете собственные программы (Shader), их нужно будет скомпилировать заново.
2. **Восстановить состояние текстур:** Phaser перезагружает основные ресурсы, но если вы работали с raw WebGL-текстурами (WebGLTexture) напрямую, их состояние нужно обновить.
3. **Выполнить логирование:** Записать в аналитику факт сбоя, чтобы отслеживать стабильность на разных устройствах.
**Важно:** Не путайте метод setContextHandlers с общими обработчиками событий сцены. Он принадлежит именно рендереру (this.game.renderer) и управляет низкоуровневыми событиями Canvas/WebGL. Стандартный жизненный цикл сцены (init, create, preload) при этом не вызывается заново.
Что попробовать дальше
Обработка восстановления WebGL-контекста — это важный шаг к созданию устойчивых игр, которые не ломаются при переключении вкладок или в сложных условиях работы браузера. Используя setContextHandlers, вы получаете контроль над этим процессом.
**Идеи для экспериментов:**
1. Попробуйте задать и первый аргумент setContextHandlers, чтобы показать пользователю сообщение "Контекст потерян, ожидайте восстановления...".
2. Свяжите восстановление контекста с перезапуском определённых анимаций или таймеров в игре.
3. Проверьте, как ведут себя ваши кастомные WebGL-объекты (буферы, фреймбуферы) после вызова обработчика.
