Оптимизация мобильной игры: что влияет на производительность

Оптимизация мобильной игры: что влияет на производительность

Производительность мобильной игры почти никогда не упирается в одну-единственную причину. Обычно это комбинация: рендеринг, память, код, физика, UI и загрузка ресурсов работают вместе, и узкое место может быть неочевидным. Если оптимизировать всё подряд без замеров, легко потратить недели и не получить заметного прироста FPS. В студии мы через это проходили не раз, и главный урок — начинать нужно с профилировщика, а не с интуиции.

Ниже — практический разбор того, что реально влияет на производительность мобильной игры в Unity, как это диагностировать и что исправлять в первую очередь. Все рекомендации основаны на реальных кейсах из разработки казуальных проектов и обучении стажёров.

Почему мобильная оптимизация отличается от ПК

На телефоне у игры обычно меньше запас по CPU, GPU и памяти, чем на десктопе. Поэтому то, что «летает» в редакторе или на мощном устройстве, может тормозить на среднем Android-смартфоне. Мы не раз наблюдали, как сцена, собранная на скорую руку, показывала 60 FPS на флагмане и 15 FPS на бюджетнике трёхлетней давности.

Ключевая ошибка новичков — ориентироваться только на FPS в Editor. Для мобильных игр важнее тестировать на целевых устройствах и сравнивать поведение на слабых и сильных моделях. В Unity прямо рекомендуют профилировать development build на реальном устройстве и проверять проект на самых слабых и самых сильных девайсах из целевой линейки. Когда я веду стажёров, первое, что заставляю сделать — запустить билд на старом телефоне и посмотреть, где именно начинаются просадки.

С чего начинать оптимизацию

Самый правильный порядок такой:

1. Найти узкое место.
2. Исправить его.
3. Снова замерить.
4. Сравнить результат до и после.

Это звучит банально, но именно так экономится время. Unity советует сохранять данные профилировщика до изменений, вносить правку и сравнивать метрики после неё. В наших проектах мы всегда делаем снапшоты профайлера перед любой серьёзной оптимизацией — это даёт объективную картину, а не ощущения «вроде стало лучше».

Что именно измерять

— Время кадра CPU.
— Время кадра GPU.
— Количество draw calls.
— Использование памяти.
— Частоту и длительность GC.
— Время загрузки сцены.
— Пики при подгрузке контента.

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

Основные источники тормозов в мобильной игре

1. Слишком дорогой рендеринг

Это один из самых частых сценариев. На телефоне важно не только «что рисуется», но и **как часто** меняется состояние рендера. Каждое переключение материала или текстуры — это накладные расходы, которые на слабом GPU быстро складываются в заметные просадки.

К рендеринговым проблемам обычно относятся:

— большое число материалов;
— много отдельных текстур вместо атласа;
— лишние прозрачные слои;
— тяжёлые шейдеры;
— избыток draw calls.

Unity в мобильной документации отдельно рекомендует держать число материалов как можно ниже, использовать texture atlases и избегать тяжёлых альфа-эффектов, особенно Cutout и больших областей прозрачности. В казуальных играх, где на экране много мелких иконок и спрайтов, это правило работает безотказно.

Что делать

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

В одном из наших проектов мы сократили число материалов с 47 до 12 только за счёт перехода на атласы и переиспользования материалов — draw calls упали почти вдвое, а FPS на слабых устройствах поднялся с 22 до 40.

2. Тяжёлые шейдеры

На мобильных устройствах шейдер должен быть максимально простым. Unity рекомендует использовать простые mobile shaders, уменьшать количество вычислений и избегать дорогих математических операций вроде pow, exp, log, sin, cos и tan. Даже одна такая операция на пиксель может стать бутылочным горлышком, если она выполняется для всего экрана.

Типичные ошибки

— многофункциональный универсальный шейдер «на все случаи жизни»;
— эффекты, которые красиво выглядят, но не дают игрового смысла;
— чрезмерное число вариантов шейдера;
— работа с высокой точностью там, где хватило бы более лёгкой.

Практика

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

3. Плохая организация батчинга

Батчинг помогает Unity объединять объекты и уменьшать количество draw calls. Это снижает нагрузку на CPU при отрисовке. В мобильных проектах это один из самых дешёвых способов получить прирост производительности без изменения логики.

Unity и связанные материалы по оптимизации выделяют несколько важных приёмов:

— Static batching для неподвижной геометрии;
— SRP Batcher в URP;
— уменьшение количества материалов;
— одинаковые настройки материалов у объектов, которые должны рисоваться вместе.

Когда батчинг ломается

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

На одном из проектов мы обнаружили, что батчинг перестал работать после того, как художник назначил каждому элементу UI свой экземпляр материала. Возврат к общему материалу и атласу мгновенно сократил draw calls на 30%.

4. Избыточная нагрузка на CPU

Если игра тормозит даже при простом рендере, проблема часто в логике: Update на тысячах объектов, частые аллокации, лишняя физика, сложные проверки каждый кадр. В мобильных играх CPU часто перегружен не графикой, а тем, что разработчик не заметил, сколько объектов висит в Update.

Unity рекомендует профилировать именно на реальном устройстве, чтобы понять, что съедает время кадра: рендер, логика, физика или память. В наших казуальных проектах мы не раз находили, что 80% времени кадра уходит на поиск объектов по имени или на обработку событий, которые можно было бы вызывать раз в секунду.

Что проверять в первую очередь

— сколько объектов живёт в Update;
— не создаются ли временные объекты каждый кадр;
— нет ли тяжёлых вычислений в циклах;
— не вызывается ли дорогая логика слишком часто;
— не перегружена ли физика.

5. Неоптимальная работа с памятью

На мобильных устройствах память заканчивается быстро. Когда игра начинает активно выделять и освобождать память, появляются фризы, а иногда и вылеты. GC может вызывать заметные подёргивания, особенно на устройствах с 2–3 ГБ ОЗУ.

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

Что обычно раздувает память

— слишком большие текстуры;
— дублирующиеся ассеты;
— неиспользуемые ресурсы в сцене;
— лишние экземпляры материалов;
— частые временные выделения в коде.

6. Большие и тяжёлые текстуры

Текстуры — один из главных потребителей памяти и пропускной способности. Unity в документации по мобильной оптимизации советует сжимать текстуры, использовать mipmaps там, где это уместно, и снижать разрешение до разумного минимума. В казуальных играх текстуры часто занимают 60–70% всей памяти, и их оптимизация даёт самый быстрый эффект.

Практический подход

— для UI и иконок — отдельные атласы;
— для фонов — уменьшение разрешения, если игрок не видит мелких деталей;
— для мелких объектов — не держать текстуры «с запасом»;
— для мобильных платформ — использовать подходящий формат сжатия.

Однажды мы уменьшили разрешение фоновых текстур на 30%, и никто из тестировщиков не заметил разницы, а потребление памяти упало на 80 МБ. Это позволило игре стабильно работать на устройствах с 2 ГБ ОЗУ.

Таблица: что сильнее всего влияет на FPS

Проблема Как проявляется Что делать
Много draw calls просадки на CPU, особенно в сценах с множеством объектов батчинг, атласы, меньше материалов
Тяжёлые шейдеры падение FPS на GPU упрощать шейдеры, убрать дорогие операции
Большие текстуры лаги, память быстро растёт сжимать, уменьшать размер, объединять в атласы
Частые аллокации фризы и подёргивания убрать мусор из Update, переиспользовать объекты
Избыточная физика нестабильный frame time снизить число коллайдеров и частоту расчётов
Сложный UI лишняя нагрузка даже в меню уменьшить анимации, слои и обновления

Практический порядок оптимизации в Unity

Шаг 1. Зафиксируйте базовую метрику

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

Шаг 2. Найдите главный bottleneck

Если CPU загружен, нет смысла первым делом переписывать шейдеры. Если GPU упирается в рендер, бессмысленно начинать с микроправок в логике. Профайлер чётко покажет, кто именно съедает кадр. В одном проекте мы думали, что проблема в физике, а оказалось — в тысяче мелких прозрачных спрайтов, которые убивали GPU.

Шаг 3. Уберите самые дорогие ошибки

Обычно это:

— слишком много материалов;
— лишняя прозрачность;
— огромные текстуры;
— аллокации в горячих местах;
— тяжёлая логика в Update.

Устранение одной такой ошибки может поднять FPS на 10–20 кадров, тогда как правка десяти мелких даст в сумме 2–3.

Шаг 4. Проверьте результат на слабом устройстве

Оптимизация ради флагмана не решает проблему массовой аудитории. В России у пользователей очень разный парк смартфонов, и ориентироваться нужно не на один «эталонный» телефон, а на несколько классов устройств. Мы тестируем на трёх-четырёх моделях: бюджетный Xiaomi трёхлетней давности, средний Samsung, флагман и что-то совсем старое с 2 ГБ ОЗУ.

Шаг 5. Повторите цикл

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

Как понять, что проблема именно в рендеринге

Есть несколько признаков:

— FPS падает, когда на экране много объектов;
— исчезновение части объектов резко улучшает производительность;
— просадки сильнее в бою, чем в меню;
— уменьшение сложности шейдера даёт заметный эффект.

Unity отдельно подчёркивает пользу batching, атласов и упрощения шейдеров как способа уменьшить CPU-накладные расходы на рендеринг. В казуальных играх рендеринг часто становится узким местом из-за обилия UI и спрайтов, поэтому мы всегда начинаем диагностику именно с него.

Быстрый чек-лист по рендеру

— [ ] В проекте минимальное число материалов.
— [ ] Мелкие спрайты собраны в атласы.
— [ ] Лишняя прозрачность убрана.
— [ ] Используются простые шейдеры.
— [ ] Проверен SRP Batcher, если проект на URP.
— [ ] Отдельно проверены статические объекты.

Как понять, что проблема в коде

Если графика простая, а игра всё равно фризит, ищите ошибку в логике. В наших проектах такое случалось, когда кто-то вставлял FindObjectOfType в Update или генерировал строки для отладки каждый кадр.

Частые причины

— создание объектов каждый кадр;
— постоянные поиски по сцене;
— тяжёлые расчёты в Update;
— частые обращения к строкам, спискам и LINQ в горячем коде;
— избыточные события и подписки.

Что помогает

— выносить расчёты из Update;
— использовать кэширование;
— переиспользовать объекты;
— сокращать частоту вызовов;
— проверять, что действительно должно выполняться каждый кадр.

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

Особенности UI в мобильной игре

UI часто недооценивают. При этом именно меню, окна, HUD и анимации могут заметно грузить слабые устройства. В казуальных проектах UI может занимать до 40% времени кадра, если сделан без оглядки на производительность.

На что смотреть

— количество активных элементов;
— анимации и эффекты;
— частоту обновления текста и прогресса;
— число отдельных атласов;
— постоянные перестроения layout.

Если интерфейс меняется редко, не стоит заставлять его пересчитываться без необходимости. Мы часто отключаем обновление текста, когда оно не видно игроку, и группируем статичные элементы на отдельных канвасах, чтобы не перестраивать весь UI при изменении одного счётчика.

Ошибки, которые чаще всего делают начинающие

— Оптимизируют без профилировки.
— Смотрят только на FPS в редакторе.
— Добавляют атлас, но оставляют десятки разных материалов.
— Пишут тяжёлые шейдеры для декоративных эффектов.
— Не замечают, что память утекает из-за текстур.
— Проверяют только один смартфон и считают результат универсальным.
— Улучшают второстепенные места, пока главный bottleneck остаётся нетронутым.

Из опыта обучения стажёров добавлю ещё одну: пытаются оптимизировать всё сразу, не фиксируя промежуточные результаты. В итоге невозможно понять, какое изменение сработало, а какое — нет.

Когда оптимизацию надо начинать

Лучше не ждать финального этапа. Базовые решения по производительности стоит закладывать ещё на стадии прототипа:

— не плодить материалы без необходимости;
— сразу думать о размере текстур;
— не строить архитектуру, где всё обновляется каждый кадр;
— тестировать на устройстве с самого начала;
— держать рендер и код в контролируемом состоянии.

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

Итог

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

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

FAQ

С чего начать оптимизацию мобильной игры в Unity?

С профилирования на реальном устройстве. Без замеров нельзя понять, что именно тормозит: рендер, CPU, память или физика. Подключите телефон, запустите development build и снимите данные профайлером — это даст точную картину.

Что сильнее всего влияет на FPS?

Обычно это количество draw calls, сложные шейдеры, тяжёлые текстуры, лишняя прозрачность и дорогая логика в коде. В казуальных играх первые два пункта часто оказываются главными виновниками.

Нужно ли всегда использовать texture atlases?

Для мобильных игр — почти всегда это хорошая идея, особенно для спрайтов, иконок и UI. Unity рекомендует атласы как способ сократить число переключений состояния и облегчить batching. Исключение — очень крупные уникальные текстуры, которые не с чем объединять.

Почему игра тормозит только на телефоне, но не в редакторе?

Потому что Editor не отражает реальную нагрузку устройства. На мобильном ограничены CPU, GPU и память, поэтому тестировать нужно на целевых девайсах. Даже мощный ПК с редактором не покажет, как игра поведёт себя на бюджетном смартфоне с медленной памятью.

Что важнее: оптимизация кода или графики?

Зависит от bottleneck. Если упираетесь в рендер — оптимизируйте графику. Если тормозит логика — сокращайте работу кода. Начинать нужно не с догадок, а с профилировщика. Он покажет, кто именно съедает кадр.

Можно ли делать красивую мобильную игру без просадок?

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