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

Наша команда Integrated Success поддерживает клиентов Unity в решении сложных технических вопросов. Мы встретились с командой старших инженеров-программистов и попросили их поделиться своим опытом в области оптимизации мобильных игр.
Наша команда Accelerate Solutions знает исходный код изнутри и работает со многими клиентами Unity, чтобы помочь им получить максимальную отдачу от движка. В своей работе они глубоко погружаются в проекты создателей, чтобы помочь определить точки, где производительность может быть оптимизирована для повышения скорости, стабильности и эффективности.
Когда наши инженеры начали делиться своими соображениями по поводу оптимизации мобильных игр, мы довольно быстро поняли, что для одного поста в блоге, который мы запланировали, слишком много отличной информации. Вместо этого мы решили превратить гору их знаний в полноценную электронную книгу (которую вы можете скачать здесь), а также в серию постов в блоге, которые освещают некоторые из этих 75+ полезных советов.
Во второй части этой серии мы подробно рассмотрим, как улучшить производительность с помощью настроек пользовательского интерфейса, физики и звука. Если вы пропустили, ознакомьтесь с нашей предыдущей статьей о профилировании, памяти и архитектуре кода, а также следите за нашей следующей статьей, посвященной активам, конфигурации проекта и графике.
Хотите все и сразу? Скачайте бесплатную электронную книгу.
Давайте приступим к делу!
Встроенная в Unity физика (Nvidia PhysX) может быть дороговата на мобильных устройствах, но следующие советы помогут вам выжать больше кадров в секунду.
В PlayerSettings отметьте Prebake Collision Meshes, когда это возможно.

Убедитесь, что вы отредактировали настройки физики(Project Settings > Physics) и упростили матрицу столкновений слоев, где это возможно .
Отключите автосинхронизацию трансформаций и включите обратные вызовы повторного использования столкновений.


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

Используйте такие методы класса, как MovePosition или AddForce, чтобы перемещать объекты Rigidbody. Прямая трансляция компонентов Transform может привести к пересчету мира физики, что очень дорого в сложных сценах. Перемещение физических тел в FixedUpdate, а не в Update.
По умолчанию в настройках проекта Fixed Timestep установлено значение 0,02 (50 Гц). Измените этот параметр в соответствии с заданной частотой кадров (например, 0,03 для 30 кадров в секунду).
Однако если частота кадров падает во время выполнения, это означает, что Unity будет вызывать FixedUpdate несколько раз за кадр и, возможно, создаст проблемы с производительностью процессора при работе с контентом, насыщенным физикой.
Максимально допустимый временной интервал ограничивает количество времени, которое могут использовать физические расчеты и события FixedUpdate в случае падения частоты кадров. Снижение этого значения означает, что во время задержки производительности физика и анимация могут замедляться, но при этом уменьшается их влияние на частоту кадров.

Используйте окно Physics Debugger(Window > Analysis > Physics Debugger) для устранения проблемных коллайдеров или несоответствий. Здесь показан цветовой индикатор GameObjects, которые могут столкнуться друг с другом.

Дополнительные сведения см. в разделе Визуализация отладки физики в документации Unity.
Unity UI (UGUI) часто может быть источником проблем с производительностью. Компонент Canvas генерирует и обновляет сетки для элементов пользовательского интерфейса и отправляет вызовы рисования на GPU. Его функционирование может быть дорогостоящим, поэтому при работе с UGUI имейте в виду следующие факторы.
Если у вас один большой холст с тысячами элементов, обновление одного элемента пользовательского интерфейса заставляет обновляться весь холст, что потенциально может привести к скачку процессора.
Воспользуйтесь возможностью UGUI поддерживать несколько холстов. Разделите элементы пользовательского интерфейса в зависимости от того, как часто их нужно обновлять. Статические элементы пользовательского интерфейса располагайте на отдельном холсте, а динамические элементы, которые обновляются одновременно, - на более мелких подхолстах.
Убедитесь, что все элементы пользовательского интерфейса в каждом холсте имеют одинаковое значение Z, материалы и текстуры.
У вас могут быть элементы пользовательского интерфейса, которые появляются в игре лишь эпизодически (например, полоска здоровья, которая появляется, когда персонаж получает урон). Если ваш невидимый элемент пользовательского интерфейса активен, он может по-прежнему использовать вызовы рисования. Явно отключите все невидимые компоненты пользовательского интерфейса и снова включите их по мере необходимости.
Если вам нужно отключить только видимость холста, отключите компонент Canvas, а не GameObjects. Это позволяет сэкономить на перестройке сетки и вершин.
Для ввода событий, таких как прикосновения к экрану или щелчки, требуется компонент GraphicRaycaster . Эта функция просто перебирает каждую точку ввода на экране и проверяет, находится ли она в пределах RectTransform пользовательского интерфейса.
Удалите GraphicRaycaster по умолчанию с верхнего холста в иерархии. Вместо этого добавьте GraphicRaycaster только к отдельным элементам, которые должны взаимодействовать (кнопки, скроллректы и так далее).

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

Группы макетов обновляются неэффективно, поэтому используйте их экономно. Избегайте их, если ваш контент не является динамичным, и используйте якоря для пропорциональных макетов. В противном случае создайте пользовательский код для отключения компонентов Layout Group после того, как они настроят пользовательский интерфейс.
Если вам необходимо использовать группы макетов (горизонтальные, вертикальные, сетчатые) для динамических элементов, избегайте их вложенности для повышения производительности.

Большие списки и сетчатые представления стоят дорого. Если вам нужно создать большой список или сетку (например, экран инвентаризации с сотнями элементов), подумайте о повторном использовании меньшего набора элементов пользовательского интерфейса, а не о создании элемента пользовательского интерфейса для каждого элемента. Посмотрите этот пример проекта на GitHub, чтобы увидеть его в действии.
Наложение множества элементов пользовательского интерфейса (например, карт, сложенных в стопку в игре "Карточные бои") приводит к перерисовке. Настройте свой код так, чтобы во время выполнения объединять многослойные элементы в меньшее количество элементов и партий.
Поскольку мобильные устройства сейчас используют разные разрешения и размеры экранов, создайте альтернативные версии пользовательского интерфейса, чтобы обеспечить наилучшую работу на каждом устройстве.
Используйте симулятор устройств для предварительного просмотра пользовательского интерфейса на широком спектре поддерживаемых устройств. Вы также можете создавать виртуальные устройства в XCode и Android Studio.

Если экран паузы или запуска закрывает все остальное в сцене, отключите камеру, которая рендерит 3D-сцену. Аналогичным образом отключите все фоновые элементы Canvas, скрытые за верхним Canvas.
Подумайте о снижении Application.targetFrameRate во время полноэкранного пользовательского интерфейса, так как вам не нужно обновляться при 60 кадрах в секунду.
Если оставить поле Event или Render Camera пустым, Unity будет вынуждена заполнить Camera.main, что неоправданно дорого.
По возможности используйте Screen Space - Overlay для режима рендеринга Canvas, так как он не требует наличия камеры.

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

Если вы используете какой-либо сжатый формат (например, MP3 или Vorbis), Unity распакует его, а затем повторно сожмет во время сборки. Это приводит к двум проходам с потерями, что ухудшает конечное качество.
Сократите размер клипов и расход памяти с помощью сжатия:
- Используйте Vorbis для большинства звуков (или MP3 для звуков, не предназначенных для зацикливания).
- Используйте ADPCM для коротких, часто используемых звуков (например, шагов, выстрелов). Это уменьшает размер файлов по сравнению с несжатым PCM, но быстро декодируется при воспроизведении.
Звуковые эффекты на мобильных устройствах должны иметь частоту не более 22 050 Гц. Использование более низких настроек обычно оказывает минимальное влияние на конечное качество; судите сами.
Настройка зависит от размера клипа.
- Небольшие клипы (< 200 кб) должны быть Decompress on Load. Это требует затрат процессора и памяти на распаковку звука в необработанные 16-битные PCM-аудиоданные, поэтому это целесообразно только для коротких звуков.
- Клипы среднего размера (>= 200 кб) должны оставаться сжатыми в памяти.
- Для больших файлов (фоновая музыка) следует установить режим Streaming, иначе в память будет загружен сразу весь актив.
При использовании кнопки отключения звука не просто установите громкость на 0. Вы можете уничтожить компонент AudioSource, чтобы выгрузить его из памяти, если плееру не нужно часто включать и выключать его.
В следующей статье блога мы погрузимся в графику и активы. Но если вы хотите получить доступ к полному списку советов и рекомендаций от команды сегодня, наша полная электронная книга доступна здесь.

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