Топ 17 практик оптимизации игры

Игрокам нравится играть в хорошие игры которые не тормозят на их железе. Но разработчики зачастую совершают одни и те же ошибки, которые ведут к низкому фпс (частота кадров в секунду) в игре.

Чтобы игра не тормозила, нужно её оптимизировать!

Топ 17 практик оптимизации игры
  • Профайлинг (Profiling)

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

В движке Unreal Engine самый полезный профайлер - Unreal Insights.

Unreal Insights | Live from HQ | Inside Unreal
  • Настройка среды под тесты производительности

Во время профайлинга вы будете сравнивать старые и новые результаты измерений.

Чтобы было проще замерять показатели рендера, можно расставить на карте (Map/Level) в нескольких местах Камеры (Camera Actor), и записывать показатели с этих камер. В итоге у вас будут максимально достоверные результаты измерений нагрузки на GPU.

Для замера нагрузки на CPU, имеет смысл изолировать объекты/акторы (Blueprint Actor) на отдельной не-игровой карте. В этом варианте на CPU не будут влиять другие системы игры/другие блюпринт-акторы, и вы получите точные замеры производительности.

В мультиплеер-играх можно записывать повторы (replays) и использовать их для профилирования. С таким подходом не нужно будет лишний раз собирать игроков онлайн для сетевого теста.

  • Задумывайтесь об оптимизации с первого дня разработки

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

  • «Сколько всего» в игре

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

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

Если в игре планируется 100 персонажей, то об этом нужно знать и помнить с самого начала разработки. В этом случае нельзя откладывать оптимизацию на потом. Если персонажей в игре тысячи, то разработку игры сразу нужно делать на C++, а не на Блюпринтах.

  • Scene Components - тяжёлые

Каждый тик в игре происходит обновление всех Акторов, Компонентов и их дочерних Компонентов. Будьте осторожны с большими иерархиями компонентов.

Очень часто разработчики навешивают на машину и на модульного-персонажа кучу компонентов, а потом удивляются, что производительность упала.

Иногда стоит рассмотреть возможность объединения Акторов, Мешей (Static Mesh) и Скелетал-мешей (Skeletal Mesh) с помощью инструментов объединения. В Unreal Engine для этого есть Merge Tool.

Skeletal Mesh Merger - Tutorial Unreal Engine 5
  • Избегайте в Блюпринтах функции Tick

Функция Tick в Блюпринтах значительно медленнее, чем в C++. Например, 100 пустых Акторов, в которых ничего не происходит, просто так тратят 1 миллисекунду процессорного времени. Если нужен Актор с функцией Tick, то желательно чтобы класс этого Актора был написан на C++. В Блюпринтах можно пользоваться Таймерами или Таймлайнами (Timeline) для временных эвентов (Time Events).

  • Включайте/отключайте Tick во время игры

Во время игры нам не всегда нужны «тикающие» Акторы. Убедитесь что Акторы и их Компоненты «тикают» только тогда, когда это действительно нужно. Пользуйтесь функцией SetActorTickEnabled.

Tick Prerequisite Actor in Unreal Engine 4
  • Снижайте Tick Rate

Большинству Акторов в игре ну нужно «тикать» раз 60 в секунду. Многие из них прекрасно работают и с более низким Tick Rate. Этот параметр можно менять прямо во время игры. Хорошей практикой будет снизить Tick Rate до 2 раз в секунду, пока объект не «активируется», тогда можно увеличить Tick Rate до максимума.

Например, Актор - Дверь или Лифт. Пока этот Актор находится в состоянии покоя, у него Tick Rate = 2. Когда мы подошли к этому Актору, пересекли его коллизию, то у него Tick Rate = 0, что значит Актор «тикает» на полной скорости.

Tick Interval in Unreal Engine 4
  • LOD для логики

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

  • «Не работай, если не смотрят»

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

Топ 17 практик оптимизации игры
  • Упрощение репликации

Сеть движка Unreal собирает объекты, находящиеся рядом с игроком, а затем проверяет их на наличие измененных свойств. Стоимость проверки измененных свойств во многом зависит от количества Акторов/Компонентов, а не от количества реплицируемых свойств. Лучше иметь PlayerCharacter со 100 реплицируемыми свойствами вместо PlayerCharacter + 9 компонентов по 10 реплицируемых свойств каждый. Это противоречит хорошей архитектуре, но нет хорошего способа обойти это.

  • Пул Акторов

В Unreal Engine создание (Spawn) Акторов очень медленный. Если для снарядов/пуль и взрывов постоянно Спавнить Акторы, то это создаст слишком большую нагрузку на Сборщик Мусора (Garbage Collector, GC).

C++ Object Pools in UE5
  • Аккуратнее с анимацией

Анимация в Unreal Engine - это известный Боттлнэк (узкое место, Bottleneck). Когда смешиваете анимации в АнимБП (AnimBP, Animation Blueprint), следите чтобы использовался быстрый путь (маленький значок молнии). Предпочитайте использовать State Machine вместо смешивания анимации через Blend.

Топ 17 практик оптимизации игры
  • Избегайте Overlap-events для движущихся объектов

Каждый компонент у которого включены Оверлап-события (Overlap-events, одна коллизия перекрывает другую коллизию), будет проверять физические перекрытия каждый раз при движении. Такие события могут срабатывать несколько раз за время 1 Draw Call.

Основное использование Оверлап-событий — для триггеров, которые определяют персонажа игрока.

Предпочитайте использовать трассировки лучей/сфер, вместо Оверлапов для снарядов/пуль и оружия, где это возможно.

  • Минимизация количества трансформаций

Каждый раз, когда вы вызываете SetLocation или SetRotation, Unreal Engine обновляет всю цепочку преобразований, и если есть физические объекты, он обновляет физику. Необходимо стремиться к строго ОДНОМУ вызову SetLocation или связанным с ним вызовам на каждый кадр движущихся объектов.

Движок Unreal имеет вызовы SetTransform и SetActorLocationAndRotation, которые позволяют изменять вращение и местоположение за один вызов вместо двух. Вызов SetActorLocationAndRotation в два раза быстрее, чем вызов SetLocation и SetRotation по отдельности.

  • Объединение логики Акторов в Менеджеры

Наличие одного Актора-Менеджера, который управляет группой других Акторов, зачастую быстрее, чем наличие у них собственной логики.

Если у вас будет большое количество чего-либо, вероятно, будет хорошей идеей объединить их с помощью какого-нибудь «менеджера», который будет обновлять все объекты. Отличные кандидаты для группировки в Менеджер: снаряды, показатели урона или некоторые части логики ИИ. Это хорошо сочетается с идеей «LOD для логики».

Aggregating Ticks to Manage Scale in Sea of Thieves | Unreal Fest Europe 2019
  • Граф репликации в Мультиплеере

Граф репликации (Replication Graph) сделали для оптимизации производительности сервера в Fortnite. Он позволяет вам переопределить логику «какие объекты имеют отношение к этому игроку». Благодаря этому, можно динамически изменять скорость обновления сети для каждой зоны на карте. И определить какие объекты находятся в диапазоне репликации.

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

При правильном использовании графа репликации вы сможете сделать игру на 200 или более игроков в многопользовательской игре.

4646
26 комментариев

Очень похоже на перевод одной статьи с форума анриала. Настолько похожа, что блок "«Сколько всего» в игре" точная копия.
Не имею ничего против перевода, но в таком случае нужно хотя бы ссылку на оригинал оставлять.

А так заметки базовые. Игнорировал их по началу, а зря.

6
Ответить

Это и есть перевод. Только сильно переработанный, адаптированный, добавлены ссылки/видосы, убрал "воду". https://dev.epicgames.com/community/learning/tutorials/3o6/expert-s-guide-to-unreal-engine-performance

4
Ответить

главный принцип оптимизации
Создавать игру на том железе на котором планируешь играть)
А то покупаешь рендер феерму а потом удивляешься почему 32гб оперативы мало и нужно 128

4
Ответить

Дада. На телефоне

1
Ответить

Так. А теперь тоже самое для юнити.
Статья отличная, но давай тоже самое под юнити с его пайплайнами)

Ответить

https://docs.unity3d.com/Manual/graphics-performance-profiling.html

Если интересна, непосредственно графика, то вот ссылка на документацию.

Там и всякие render pass, draw calls, batching все есть, с этого точно можно начать)

1
Ответить