Раскройте потенциал WebGL с помощью бесконечных процедурно генерируемых пейзажей этой казуальной гоночной игры.
Slow Roads — это казуальная гоночная игра с упором на бесконечно процедурно генерируемые пейзажи, размещенные в браузере в виде приложения WebGL . Многим такой интенсивный опыт может показаться неуместным в ограниченном контексте браузера — и действительно, изменение такого отношения было одной из моих целей в этом проекте. В этой статье я расскажу о некоторых методах, которые я использовал для преодоления препятствий производительности в своей миссии, чтобы подчеркнуть часто упускаемый из виду потенциал 3D в Интернете.
3D разработка в браузере
После выпуска Slow Roads я увидел в отзывах повторяющийся комментарий: «Я не знал, что это возможно в браузере». Если вы разделяете это мнение, вы определенно не меньшинство; Согласно опросу State of JS 2022 года , около 80% разработчиков еще не экспериментировали с WebGL. Мне немного жаль, что такой большой потенциал может быть упущен, особенно когда дело касается браузерных игр. С помощью Slow Roads я надеюсь привлечь внимание к WebGL и, возможно, уменьшить количество разработчиков, которые недовольны фразой «высокопроизводительный игровой движок JavaScript».
WebGL может показаться многим загадочным и сложным, но за последние годы его экосистема разработки значительно превратилась в высокофункциональные и удобные инструменты и библиотеки. Теперь фронтенд-разработчикам стало проще, чем когда-либо, включить 3D UX в свою работу, даже без предварительного опыта работы с компьютерной графикой. Three.js , ведущая библиотека WebGL, служит основой для многих расширений, включая React-three-fiber , который добавляет 3D-компоненты в среду React. Сейчас также существуют комплексные веб-редакторы игр, такие как Babylon.js или PlayCanvas , которые предлагают знакомый интерфейс и интегрированные наборы инструментов.
Однако, несмотря на замечательную полезность этих библиотек, амбициозные проекты в конечном итоге сталкиваются с техническими ограничениями. Скептики, относящиеся к браузерным играм, могут подчеркнуть, что JavaScript является однопоточным и ограничен в ресурсах. Но преодоление этих ограничений открывает скрытую ценность: ни одна другая платформа не предлагает такой же мгновенной доступности и массовой совместимости, как браузер. Пользователи любой системы с поддержкой браузера могут начать играть в один клик, без необходимости устанавливать приложения и входить в сервисы. Не говоря уже о том, что разработчики наслаждаются элегантным удобством наличия надежных интерфейсных платформ для создания пользовательского интерфейса или управления сетью для многопользовательских режимов. Эти ценности, на мой взгляд, и делают браузер такой превосходной платформой как для игроков, так и для разработчиков, и, как показывает Slow Roads, технические ограничения часто могут быть сведены к проблеме дизайна.
Достижение плавности хода на медленных дорогах
Поскольку основные элементы «Медленных дорог» включают высокоскоростное движение и дорогостоящую генерацию декораций, необходимость плавной работы подчеркивала каждое мое дизайнерское решение. Моя основная стратегия заключалась в том, чтобы начать с урезанного дизайна игрового процесса, который позволял использовать контекстные сокращения в архитектуре движка. С другой стороны, это означает отказ от некоторых приятных функций в поисках минимализма, но в результате получается сделанная на заказ гипероптимизированная система, которая прекрасно работает в разных браузерах и устройствах.
Ниже приводится разбивка ключевых компонентов, которые обеспечивают экономичность «Медленных дорог».
Формирование движка окружения вокруг игрового процесса
Являясь ключевым компонентом игры, движок генерации окружения неизбежно дорог и оправданно отнимает наибольшую долю ресурсов памяти и вычислений. Используемый здесь трюк заключается в планировании и распределении тяжелых вычислений в течение определенного периода времени, чтобы не прерывать частоту кадров из-за скачков производительности.
Окружающая среда состоит из геометрических фрагментов, различающихся по размеру и разрешению (отнесенным к категории «уровни детализации» или LoD) в зависимости от того, насколько близко они будут отображаться перед камерой. В типичных играх со свободно перемещаемой камерой необходимо постоянно загружать и выгружать различные LoD, чтобы детализировать окружение игрока, куда бы он ни пошел. Это может оказаться дорогостоящей и расточительной операцией, особенно если сама среда генерируется динамически. К счастью, в «Медленных дорогах» это соглашение можно полностью нарушить благодаря контекстуальному ожиданию, что пользователь должен оставаться на дороге. Вместо этого высокодетализированную геометрию можно оставить для узкого коридора, примыкающего непосредственно к маршруту.
![Диаграмма, показывающая, как заблаговременное создание дороги может обеспечить упреждающее планирование и кэширование создания среды.](https://web.developers.google.cn/static/case-studies/slow-roads/image/a-diagram-showing-genera-8bc6e65c0bba1.png?authuser=8&hl=ru)
Средняя линия дороги генерируется задолго до прибытия игрока, что позволяет точно предсказать, когда и где потребуются детали окружающей среды. Результатом является экономичная система, которая может заранее планировать дорогостоящую работу, генерируя только минимум, необходимый в каждый момент времени, и не тратя усилий на детали, которые не будут видны. Этот метод возможен только потому, что дорога представляет собой единый, неразветвляющийся путь — хороший пример поиска компромиссов в игровом процессе, учитывающих архитектурные упрощения.
![Диаграмма, показывающая, как заблаговременное создание дороги может обеспечить упреждающее планирование и кэширование создания среды.](https://web.developers.google.cn/static/case-studies/slow-roads/image/a-diagram-showing-genera-a22a99a5764f2.png?authuser=8&hl=ru)
Быть разборчивым в отношении законов физики
Вторым после вычислительных требований движка среды является физическое моделирование. В Slow Roads используется собственный минимальный физический движок, который использует все доступные короткие пути.
Основная экономия здесь заключается в том, чтобы в первую очередь избегать моделирования слишком большого количества объектов — опираясь на минимальный контекст дзен, игнорируя такие вещи, как динамические столкновения и разрушаемые объекты. Предположение о том, что транспортное средство останется на дороге, означает, что столкновения с внедорожными объектами можно разумно игнорировать. Кроме того, кодирование дороги как разреженной средней линии позволяет использовать элегантные приемы для быстрого обнаружения столкновений с поверхностью дороги и ограждениями, и все это на основе проверки расстояния до центра дороги. Вождение по бездорожью становится дороже, но это еще один пример справедливого компромисса, подходящего для контекста игрового процесса.
Управление объемом памяти
Будучи еще одним ресурсом, ограниченным браузером, важно бережно относиться к памяти, несмотря на то, что JavaScript занимается сборкой мусора. Это легко упустить из виду, но объявление даже небольших объемов новой памяти в игровом цикле может привести к серьезным проблемам при работе на частоте 60 Гц. Помимо съедания ресурсов пользователя в контексте, когда он, вероятно, выполняет несколько задач, большие сборки мусора могут занимать несколько кадров, что приводит к заметным подтормаживаниям. Чтобы избежать этого, память цикла может быть предварительно выделена в переменных класса при инициализации и перезагружена в каждом кадре.
![Просмотр профиля памяти «до» и «после» во время оптимизации кодовой базы Slow Roads, показывающий значительную экономию и снижение скорости сборки мусора.](https://web.developers.google.cn/static/case-studies/slow-roads/image/a-before-after-view-the-f870ec7d3c94f.png?authuser=8&hl=ru)
Также очень важно, чтобы более тяжелые структуры данных, такие как геометрии и связанные с ними буферы данных, управлялись экономично. В бесконечно генерируемой игре, такой как Slow Roads, большая часть геометрии существует на своего рода беговой дорожке: как только старый фрагмент отстает вдалеке, его структуры данных могут быть сохранены и повторно использованы для следующего фрагмента мира, дизайна. шаблон, известный как пул объектов.
Эти методы помогают расставить приоритеты в бережливом исполнении, жертвуя некоторой простотой кода. В контексте высокой производительности важно помнить о том, что удобные функции иногда заимствуются у клиента в интересах разработчика. Например, такие методы, как Object.keys()
или Array.map()
невероятно удобны, но легко упустить из виду, что каждый из них создает новый массив для возвращаемого значения. Понимание внутренней работы таких черных ящиков может помочь улучшить ваш код и избежать скрытых потерь производительности.
Сокращение времени загрузки с помощью процедурно генерируемых ресурсов.
Хотя производительность во время выполнения должна быть главной заботой разработчиков игр, обычные аксиомы относительно времени начальной загрузки веб-страницы по-прежнему остаются верными. Пользователи могут быть более снисходительными при сознательном доступе к тяжелому контенту, но длительное время загрузки все равно может отрицательно сказаться на опыте, если не на удержании пользователей. Играм часто требуются большие ресурсы в виде текстур, звуков и 3D-моделей, и как минимум их следует тщательно сжимать там, где можно сэкономить на деталях.
В качестве альтернативы, процедурное создание активов на клиенте может в первую очередь избежать длительных передач. Это огромное преимущество для пользователей с медленными соединениями и дает разработчику более прямой контроль над тем, как устроена их игра — не только на начальном этапе загрузки, но и когда дело доходит до адаптации уровней детализации для различных настроек качества.
Большая часть геометрии в Slow Roads генерируется процедурно и упрощена, а специальные шейдеры комбинируют несколько текстур для передачи деталей. Недостаток заключается в том, что эти текстуры могут быть тяжелым ресурсом, хотя здесь есть дополнительные возможности для экономии с помощью таких методов, как стохастическое текстурирование, позволяющих добиться большей детализации из небольших исходных текстур. А на крайнем уровне также возможно генерировать текстуры полностью на клиенте с помощью таких инструментов, как texgen.js . То же самое справедливо даже для аудио: API веб-аудио позволяет генерировать звук с помощью аудиоузлов.
Благодаря использованию процедурных активов создание исходной среды занимает в среднем всего 3,2 секунды. Чтобы наилучшим образом воспользоваться преимуществом небольшого размера предварительной загрузки, простой экран-заставка приветствует новых посетителей и откладывает дорогостоящую инициализацию сцены до тех пор, пока не будет подтверждено нажатие кнопки. Это также действует как удобный буфер для возвращенных сеансов, сводя к минимуму ненужную передачу динамически загружаемых ресурсов.
Гибкий подход к поздней оптимизации
Я всегда считал кодовую базу Slow Roads экспериментальной и поэтому придерживался очень гибкого подхода к разработке. При работе со сложной и быстро развивающейся системной архитектурой может быть сложно предсказать, где могут возникнуть важные узкие места. Основное внимание следует уделять быстрой, а не чистой реализации желаемых функций, а затем работать в обратном направлении для оптимизации систем там, где это действительно важно. Профилировщик производительности в Chrome DevTools неоценим на этом этапе и помог мне диагностировать некоторые серьезные проблемы с более ранними версиями игры. Ваше время как разработчика ценно, поэтому убедитесь, что вы не тратите время на размышления о проблемах, которые могут оказаться незначительными или излишними.
Мониторинг пользовательского опыта
При реализации всех этих трюков важно быть уверенным, что игра в реальных условиях работает так, как ожидается. Использование широкого спектра аппаратных возможностей является основным аспектом разработки любой игры, но веб-игры могут быть ориентированы на гораздо более широкий спектр, включающий одновременно как топовые настольные компьютеры, так и мобильные устройства десятилетней давности. Самый простой способ добиться этого — предложить настройки для адаптации наиболее вероятных узких мест в вашей кодовой базе (как для задач с интенсивным использованием графического процессора, так и для процессора), как показывает ваш профилировщик.
Однако профилирование на вашем собственном компьютере может охватить лишь ограниченный объем информации, поэтому полезно каким-то образом замкнуть цикл обратной связи с вашими пользователями. Для Slow Roads я использую простую аналитику, которая сообщает о производительности, а также о контекстных факторах, таких как разрешение экрана. Эти аналитические данные отправляются на базовый сервер Node с помощью Socket.io вместе с любыми письменными отзывами, которые пользователь отправляет через внутриигровую форму. Вначале эта аналитика выявила множество важных проблем, которые можно было устранить с помощью простых изменений в пользовательском интерфейсе, таких как подсветка меню настроек при обнаружении постоянно низкого FPS или предупреждение о том, что пользователю может потребоваться включить аппаратное ускорение, если производительность особенно плохая.
Впереди медленные дороги
Даже после принятия всех этих мер остается значительная часть игроков, которым приходится играть на более низких настройках — в первую очередь те, кто использует легкие устройства без графического процессора. Хотя диапазон доступных настроек качества обеспечивает довольно равномерное распределение производительности, только 52% игроков достигают скорости выше 55 FPS.
![Матрица, определяемая настройкой расстояния просмотра в зависимости от настройки детализации, показывающая среднее количество кадров в секунду, достигнутое при различных сочетаниях. Распределение довольно равномерно распределено между 45 и 60, при этом 60 является целевым показателем для хорошей производительности. Пользователи с низкими настройками, как правило, видят более низкий FPS, чем пользователи с высокими настройками, что подчеркивает различия в возможностях клиентского оборудования.](https://web.developers.google.cn/static/case-studies/slow-roads/image/a-matrix-defined-view-di-5c73d8d72469c.png?authuser=8&hl=ru)
К счастью, существует еще много возможностей для экономии производительности. Помимо добавления дополнительных приемов рендеринга для снижения спроса на графические процессоры, я надеюсь в ближайшем будущем поэкспериментировать с веб-работниками по распараллеливанию генерации среды и, возможно, в конечном итоге увидеть необходимость включения WASM или WebGPU в базу кода. Любое свободное пространство, которое я смогу освободить, позволит создать более богатую и разнообразную среду, что станет постоянной целью оставшейся части проекта.
Что касается хобби-проектов, Slow Roads стал чрезвычайно полезным способом продемонстрировать, насколько удивительно сложными, производительными и популярными могут быть браузерные игры. Если мне удалось заинтересовать вас WebGL, знайте, что технологически Slow Roads — это довольно поверхностный пример его полных возможностей. Я настоятельно рекомендую читателям изучить презентацию Three.js , а тех, кто интересуется разработкой веб-игр, мы будем рады приветствовать в сообществе на webgamedev.com .