Hero background image
Советы по оптимизации пользовательского интерфейса Unity
Узнайте, как полностью оптимизировать пользовательский интерфейс: советы по разделению холстов и групп макетов, объединению объектов пользовательского интерфейса и многое другое.

Это одна из нескольких страниц с подробным руководством по оптимизации игр для ПК и консолей. Полную коллекцию вы найдете в бесплатной электронной книге, Оптимизируйте производительность игр на консолях и ПКв которой содержится более 80 полезных советов и лучших практик по оптимизации производительности.

Разделите холсты

Проблема: Когда на UI Canvas изменяется один элемент, он загрязняет весь Canvas.

Холст - это основной компонент пользовательского интерфейса Unity. Он генерирует сетки, представляющие элементы пользовательского интерфейса, размещенные на нем, регенерирует сетки при изменении элементов пользовательского интерфейса и выполняет вызовы рисования на GPU, чтобы пользовательский интерфейс действительно отображался.

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

Многие пользователи строят весь пользовательский интерфейс игры на одном Canvas с тысячами элементов. При изменении одного элемента может произойти скачок процессора на несколько миллисекунд. Чтобы узнать больше о том, почему восстановление так дорого, перейдите на отметку 24:55 в этой сессии Unite.

Решение Разделите холсты на части.

Каждый холст - это остров, который изолирует свои элементы от элементов других холстов. Воспользуйтесь возможностью UGUI поддерживать несколько холстов, разбив их на части, чтобы решить проблемы с пакетной обработкой в Unity UI.

Вы также можете вложить холсты, что позволяет дизайнерам создавать большие иерархические пользовательские интерфейсы, не задумываясь о том, где находятся различные элементы на экране в разных холстах. Дочерние холсты также изолируют содержимое от родительских холстов и холстов братьев и сестер. Они поддерживают собственную геометрию и осуществляют дозирование. Один из способов решить, как их разделить, - это определить, как часто их нужно обновлять. Статические элементы пользовательского интерфейса располагайте на отдельном холсте, а динамические элементы, которые обновляются одновременно, - на небольших подхолстах. Также убедитесь, что все элементы пользовательского интерфейса на каждом холсте имеют одинаковое значение Z, материалы и текстуры.

Интерфейс Graphic Raycaster
Ограничение графических излучателей и отключение цели излучения

Проблема: Неадекватное использование графического рейсфедера

Graphic Raycaster - это компонент, который преобразует ваши данные в события пользовательского интерфейса. Если говорить точнее, он преобразует нажатия на экран или сенсорные вводы в события пользовательского интерфейса, а затем отправляет их на соответствующие элементы пользовательского интерфейса. Графический райзер нужен на каждом холсте, требующем ввода, включая подхолсты. Однако при этом происходит циклический просмотр каждой точки ввода на экране и проверка их нахождения в пределах RectTransform пользовательского интерфейса, что приводит к потенциальным накладным расходам.

Несмотря на свое название, Graphic Raycaster на самом деле не является рейкастером. По умолчанию он тестирует только графику пользовательского интерфейса. Он берет набор элементов пользовательского интерфейса, которые заинтересованы в получении ввода на данном холсте, и выполняет проверку на пересечение. Например, он проверяет, отмечена ли точка, в которой происходит событие ввода, относительно RectTransform каждого элемента пользовательского интерфейса на графическом холсте Raycaster как интерактивная.

Проблема в том, что не все UI Elements заинтересованы в получении обновлений.

Решение Удалите графические излучатели с неинтерактивных полотен пользовательского интерфейса и отключите цель излучения для статичных или неинтерактивных элементов.

В частности, текст на кнопке, отключающей Raycast Target, напрямую уменьшит количество проверок пересечений, которые графический Raycaster должен выполнять на каждом кадре.

Проблема: Иногда Graphic Raycaster действительно действует как raycaster.

Если вы установите режим рендеринга на холсте в Worldspace Camera или Screen Space Camera, вы можете добавить блокирующую маску. Маска блокировки определяет, будет ли Raycaster отбрасывать лучи с помощью 2D- или 3D-физики, чтобы определить, блокирует ли какой-либо физический объект возможность пользователя взаимодействовать с пользовательским интерфейсом.

Решение Создание лучей с помощью 2D- или 3D-физики может быть дорогостоящим, поэтому используйте эту функцию осторожно.

Сведите к минимуму количество Graphic Raycasters, исключив их из неинтерактивных UI Canvases, поскольку в этом случае нет смысла проверять события взаимодействия.

Подробнее о Graphic Raycaster читайте в этой документации.

Grid-интерфейс
Избегайте дорогих элементов пользовательского интерфейса

Проблема: Большие списки, сетчатые представления и многочисленные наложенные элементы пользовательского интерфейса требуют больших затрат.

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

Решение Избегайте многочисленных наложенных друг на друга элементов пользовательского интерфейса.

Настройте свой код для объединения многослойных элементов пользовательского интерфейса во время выполнения в меньшее количество элементов и пакетов.

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

Посмотрите этот проект на GitHub, чтобы увидеть пример оптимизированного списка прокрутки.

Интерфейс групп макетов
По возможности избегайте групп компоновки

Проблема: Каждый элемент пользовательского интерфейса, который пытается изменить свой макет, выполнит как минимум один вызов GetComponent.

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

Система компоновки - это набор смежных групп компоновки, расположенных непосредственно над элементом компоновки. Элемент макета - это не просто компонент Layout Element (изображения, тексты и Scroll Rects), он также включает в себя элементы макета - так же как Scroll Rects являются группами макетов.

Теперь о проблеме: Каждый элемент пользовательского интерфейса, пометивший свой макет как "грязный", выполнит как минимум один вызов GetComponent. Этот вызов ищет действительную группу компоновки в родительском элементе компоновки. Если он находит такую группу, то продолжает двигаться вверх по иерархии Transform, пока не прекратит поиск групп компоновки или не достигнет корня иерархии; в зависимости от того, что наступит раньше. Таким образом, каждая группа макетов добавляет один вызов GetComponent к процессу загрязнения каждого дочернего элемента макета, что делает вложенные группы макетов очень плохими с точки зрения производительности.

Решение По возможности избегайте групп раскладки.

Используйте якоря для пропорциональной раскладки. Для горячих пользовательских интерфейсов с динамическим количеством элементов пользовательского интерфейса рассмотрите возможность написания собственного кода для расчета макетов. Используйте его по требованию, а не для каждого изменения.

Подробнее о группах макетов можно узнать из нашей документации.

Интерфейс объединения объектов
Объекты пользовательского интерфейса в пуле - умный способ

Проблема: Объединение объектов пользовательского интерфейса в пул - неправильный путь

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

Решение Сначала отключите объект, а затем перенаправьте его в пул.

Вы испачкаете старую иерархию один раз, но, сделав репарт, вы не будете пачкать старую иерархию второй раз, а новую иерархию не будете пачкать вообще. Если вы удаляете объект из пула, сначала сделайте его репарт, обновите данные, а затем включите его.

Узнайте больше о концепциях базового пула объектов в Unity.

Компонент UI Canvas
Как скрыть холст

Проблема: Не знаю, как скрыть холст

Иногда полезно скрывать элементы пользовательского интерфейса и холсты. Но как сделать это эффективно?

Решение Отключите сам компонент Canvas.

Отключение компонента Canvas не позволит ему отправлять вызовы рисования на GPU. Таким образом, холст больше не будет виден. Однако Canvas не будет удалять свой вершинный буфер, он сохранит все свои сетки и вершины. Тогда при повторном включении он не будет вызывать перестройку - он просто начнет рисовать их снова.

Кроме того, отключение компонента Canvas не вызывает дорогостоящих обратных вызовов OnDisable/OnEnable через иерархию Canvas. Только не забудьте отключить дочерние компоненты, в которых выполняется дорогостоящий покадровый код.

Подробнее о компоненте Canvas можно узнать здесь.

Оптимальное использование аниматоров в элементах пользовательского интерфейса

Проблема: Использование аниматоров в пользовательском интерфейсе

Аниматоры будут пачкать свои элементы пользовательского интерфейса на каждом кадре, даже если значение в анимации не меняется.

Решение Используйте код для анимации пользовательского интерфейса.

Ставьте аниматоры только на динамические элементы пользовательского интерфейса, которые постоянно меняются. Для элементов, которые редко меняются или меняются временно в ответ на события, напишите свой собственный код или используйте систему tweening. В Asset Store есть несколько отличных решений для этого.

При использовании полноэкранного пользовательского интерфейса скрывайте все остальное

Проблема: Низкая производительность при полноэкранном пользовательском интерфейсе

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

Решение Спрячьте все остальное.

Если экран закрывает все остальное в сцене, отключите функцию Camera rendering the 3D scene. Аналогичным образом отключите элементы Canvas, скрытые за верхним Canvas.

Подумайте о снижении Application.targetFrameRate во время полноэкранного пользовательского интерфейса, поскольку вам не нужно обновлять данные при 60 кадрах в секунду.

Дополнительные ресурсы
Оптимизация производительности игр
Получите бесплатную электронную книгу, чтобы узнать больше

Обеспечьте своим игрокам наилучший игровой опыт. Более 80 действенных советов и лучших практик от инженеров-экспертов Unity позволят вам оптимизировать игры для ПК и консолей.

Созданные инженерными командами Unity Success и Accelerate Solutions, эти подробные рекомендации, собранные из реальных примеров работы с ведущими студиями, помогут повысить общую производительность вашей игры.

Было ли это содержание полезным?