Как многим из вас известно, полное издание Phoenix Point — Phoenix Point: Year One Edition, выходит в Steam (не забудьте добавить в список желаемого!) и на консолях (о сроках мы расскажем в другой раз), и мы с нетерпением ожидаем момента, когда вы сможете испытать весь опыт, который может дать наша игра. В последние месяцы основными задачами, стоящими перед студией, были постоянная оптимизация игры, исправление ряда существующих технических проблем и улучшение игры с каждым обновлением
Привет, я Нед – программист Snapshot Games, специализирующийся на геймплее/пользовательском интерфейсе, и я вернулся к вам с рассказом об интересных проблемах оптимизации, который мне не терпится вам поведать!
Если вы пропустили мой предыдущий пост – зацените! Он был написан ещё в мае и касался обсуждения некоторых проблем, возникших у нас при разработке контента для бэкеров.
Что же, после всего сказанного, давайте наконец отправимся дальше… в менее отдалённые времена!
Задача, стоящая перед нами во время оптимизационных забегов, была «простой»: играть с запущенным Unity Profiler и исследовать каждый всплеск или сбой, выискивая признаки того, что что-то на экране требует больше ресурсов или времени, чем необходимо для отображения. Хотя эти проблемы не ломали игру полностью, они всё ещё способны испортить впечатление от игры. Кроме того, на слабые ПК эти проблемы имеют гораздо большее влияние, чем на более мощные.
Позвольте мне на правах участника команды Geoscape показать вам некоторые интересные проблемы, которые мы с удивлением обнаружили… и исправили сразу после того, как нашли.
Когда я играл, то обратил внимание, что несколько раз одно событие занимает большую часть фрейма для своего решения:
Давайте копнём глубже, что же такое с EventSystem.Update() и EventSystem.RaycastAll()?
Так же, как и в случае с многими другими вещами, связанными с разработкой игр, некоторые из основных систем в игре должны обновляться каждый фрейм, чтобы игра могла реагировать и отзываться на вводимую пользователем информацию или иные действия, происходящие на экране. EventSystem.Update () обновляет каждый фрейм и отвечает за обновление системы событий Unity, обрабатывающей вводимые данные и такие действия как, например, взаимодействие курсора при наведении на элементы интерфейса, и рейкастинг для большинства объектов сцен.
Итак, с учётом сказанного, что делает EventSystem.RaycastAll ()? Каждый раз, когда вы щёлкаете мышью, система событий Unity «проверяет» или выполняет рейкастинг, пытаясь определить, где именно на экране вы кликнули. Большинство объектов пользовательского интерфейса в Unity, таких как объекты Text и Image, имеют флаг, помечающий их как цель, которая имеет доступ к рейкастингу. Так что чем больше у вас на экране целевых объектов с рейкастингом, тем больше работы для Unity.
После этого объяснения проблема стала ясна. На некоторых экранах меню геолокации у нас больше целей рейкастинга, чем нужно. Вот общий совет по оптимизации пользовательского интерфейса Unity: сократите количество целей рейкастинга и оставьте только те объекты, которым он действительно нужен.
Вооружившись написанным моим коллегой инструментом, который выделяет на экране все доступные элементы пользовательского интерфейса с возможностью рейкастинга, я продолжил поиск.
Позвольте мне продемонстрировать вам некоторые из моих выводов.
Экран дипломатии, каким мы его знаем:
Взгляд через инструмент на все доступные элементы с возможностью рейкастинга:
Слишком много целей рейкастинга. Когда Unity пытается определить, где вы нажали, он проверяет каждую из них!
Вот результаты после отключения ненужных элементов:
Экран встреч в разделе геолокации:
На большинстве экранов геолокации у нас есть специальный объект рейкастинга, который предотвращает ввод части данных; например, он не позволяет вам вращать глобус, когда открыт полноэкранный интерфейс. Он выглядит как большой красный прямоугольник, занимающий весь экран. Но, даже если мы исключим блокировщик ввода, то вы можете заметить, что часть текста, некоторые другие графические элементы, с которыми невозможно взаимодействовать, могут быть целью рейкастинга. После отключения ненужных объектов рейкастинга, нажатия будут влиять только на кнопки и блокировщик ввода:
Кроме того, оказалось, что всплывающие подсказки в меню базы PX на экране геоскейпа всегда будут отвечать на ваши нажатия. Даже если вы не можете с ними взаимодействовать.
И есть еще множество ненужных целей рейкастинга, которые были повсюду. Но почему так происходит? Когда вы создаете объекты пользовательского интерфейса, Unity по умолчанию помечает их как цель рейкастинга, и с этим нужно быть очень внимательным. Мораль истории — грамотно управляйте своими рейкастами!
К следующему пункту!
Команда заметила, что в разных случаях профайлер отмечал всплеск в моменты, когда игрок увеличивал или уменьшал масштаб, находясь на главном экране геолокации. Чем это было вызвано?
На сей раз функция, вызвавшая проблему, не имела ничего общего с Unity. При более глубоком изучении выяснилось, что она отвечает за значки информации участков карты (ресурсы, доступные рекруты), которые отображаются при увеличении масштаба и скрываются, когда вы отдаляете глобус.
Почему UpdateForFov () вызывал проблемы?
- Оказалось, что основные валидации для этого действия будут вызываться каждый фрейм, даже если вы не находитесь на основном экране геоскейпа.
- Поскольку у этой функции была установлена проверка, чтобы все время не включать и не отключать визуальные эффекты в каждом фрейме, то, каждый раз, когда выполнялись условия валидации, UpdateForFov () просматривал все участки (около 439) на глобусе и пытался включать/отключать их визуальные эффекты.
Что мы сделали? Правильно, добавили ещё больше валидаций!
- Теперь UpdateForFov () может быть вызван только когда игрок находится только на основном экране геоскейпа.
- Участки теперь могут отображать информацию только в том случае, если они работают, видны и проверяются игроком.
Хотя подобные проблемы не являются чем-то из ряда вон выходящим, а их решения довольно просты, их может быть очень много и они имеют большое влияние на производительность. Так что всегда хорошо:
- Придерживаться определённой логики, влияющей на множество объектов только тогда, когда это необходимо и выполняются определённые условия. Невозможно следовать этому правилу каждый раз, но, по крайней мере, постарайтесь максимально ограничить исключения из него.
- Обновлять состояния/визуальные эффекты объектов, таким образом, чтобы они выполнялись группами или небольшими порциями за раз. Например:
- Разделяйте инициализацию/обновление между разными фреймами.
- Показывайте/обновляйте только то, что может видеть игрок.
- Показывать за раз только небольшой пакет данных (прокручивающаяся виртуализация).
Поскольку мы постоянно внедряем новые функции, нам необходимо стараться исправлять любые проблемы, которые могут возникнуть, так, например:
- Нам пришлось добавить больше полотен в пользовательский интерфейс там, где это было необходимо.
- Нам пришлось очистить и сократить некоторые иерархии элементов пользовательского интерфейса, которые мы использовали.
- Мы обнаружили несколько затратных операций, которые часто выполнялись — мы кэшировали многие из них, а так же их результаты, чтобы все это можно было повторно использовать.
- Нам пришлось разделить несколько инициализаций и вычислений на разные фреймы, чтобы избежать скачков и сбоев.
И моя работа ещё не закончена! По мере того, как мы приближаемся к выпуску Year One Edition, у нас есть и другие улучшения игры, а также новые функции и контент, которые помогут вам отлично провести время, когда вы испытаете игру на выбранной вами платформе!
До скорого!