~4 мин чтения

Сборка и оптимизация

Build Settings, Profiler, бюджет кадра — от готового прототипа к билду.

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

Build Settings

File → Build Profiles (в Unity 6 — новое имя; раньше Build Settings):

  1. Platform — Windows / macOS / Linux / Android / iOS / WebGL / Console.
  2. Scenes in Build — список сцен (по индексу). SceneManager.LoadScene(0) — первая.
  3. Build или Build And Run — собирает в указанную папку.

Для каждой платформы свои Player Settings (Edit → Project Settings → Player):

  • Имя продукта, иконка, splash screen.
  • Scripting Backend: Mono vs IL2CPP (см. главу про стек).
  • API Compatibility Level — .NET Standard 2.1 (рекомендуется).
  • Managed Stripping Level — насколько агрессивно линкер выкидывает “неиспользуемый” код.
Linker и рефлексия

Managed Stripping = High может выкинуть код, который используется только через рефлексию или Unity Events. Если после билда что-то “пропадает”, попробуйте Low/Disabled. Долгосрочное решение — link.xml или атрибут [Preserve] на нужных типах.

Бюджет кадра

Для 60 FPS у вас 16.6 мс на кадр. Из них:

  • 2–4 мс обычно уходит на рендеринг сцены и постпроцесс (GPU).
  • 2–6 мс — physics + animation + ваши скрипты (CPU).
  • Остаток — buffer, GC, VSync.

На 30 FPS — 33.3 мс. Для VR с 90 FPS — 11.1 мс и без права на просадки.

Profiler

Window → Analysis → Profiler. Запустите Play, остановитесь на интересном кадре. Смотрите:

  • CPU Usage — стек вашего кода: что съело время.
  • GPU Usage — какой проход рендера сколько занял.
  • Rendering — количество draw call’ов, треугольников, batches.
  • Memory — общая память, allocations.

Главный враг — GC Alloc в Update. Каждая аллокация (new string, new List<>, Vector3.ToString()) рано или поздно вызовет паузу сборщика мусора. Цель — 0 байт аллокаций в стабильном gameplay.

// Плохо: каждый кадр строит новую строку и LINQ-цепочку
private void Update() {
    var alive = enemies.Where(e => e.IsAlive).ToList();
    label.text = "Враги: " + alive.Count;
}

// Хорошо: счётчик ведётся событиями, строка — через struct-формат
private int _aliveCount;
private static readonly System.Text.StringBuilder _sb = new();

private void Update() {
    _sb.Clear();
    _sb.Append("Враги: ").Append(_aliveCount);
    label.SetText(_sb); // TMP принимает StringBuilder без аллокаций
}

Frame Debugger

Window → Analysis → Frame Debugger. Останавливает рендеринг на любом draw call и показывает: какой меш, материал, текстуры, render target. Лучший способ понять, почему 800 draw call’ов на простой сцене.

Типичные находки:

  • Одинаковые материалы, которые не батчатся (instance-копии материалов).
  • UI-канвасы, которые пересобираются каждый кадр.
  • Десятки маленьких источников света с теневыми проходами.
  • Постпроцесс, отключаемый только в одной из сцен.

Workflow профайлера — CPU, GPU, Rendering, Memory

Профайлер — это не “включил и смотришь”. Эффективный workflow:

  1. Подготовьте target-сцену — пусть она представительна для real gameplay (битва, перемещение по миру). Прогрейте 10 секунд, чтобы GC stabilized.
  2. Откройте Profiler в Standalone режиме (Profiler → Edit → Profile Standalone поверх dev build на target-устройстве). Editor-профайлинг скрывает многие реальные проблемы.
  3. Включите Deep Profile только если общий показывает hot path в “unknown” — Deep даёт детализацию ценой ×3–10 overhead.
  4. Изучите CPU Usage сначала — там видно фреймы дольше 16.6 мс. Кликаете → видите callstack.
  5. Если CPU чист — Rendering & GPU Usage — кадры могут “застревать” на vsync waiting GPU.

Profiler Markers — свои метки

using Unity.Profiling;

public class EnemyManager : MonoBehaviour
{
    static readonly ProfilerMarker s_UpdateAllMarker = new("EnemyManager.UpdateAll");

    private void Update() {
        using (s_UpdateAllMarker.Auto()) {
            // ваш hot-path code
        }
    }
}

Маркер появится в Profiler как именованная секция. Незаменимо для понимания “что съело время” внутри своего кода.

Memory Profiler — глубокий аудит памяти

Отдельный пакет (Memory Profiler). Делает снапшоты памяти и сравнивает между ними. Помогает найти:

  • Утечки текстур (например, материал, склонированный через renderer.material и не освобождённый).
  • Загруженные сцены, не выгруженные из памяти.
  • Asset bundles, которые остались висеть.

Размер билда

Главные источники веса:

  1. Текстуры — самое большое. Compress (ASTC для Android, BC для PC). Не кладите 4K-текстуры на объект, который занимает 50 пикселей на экране.
  2. Аудио — длинные wav-треки. Streaming + Vorbis вместо raw PCM.
  3. Меши — у моделей с миллионом вершин. Decimate в Blender, или используйте LOD-группы.
  4. Скрипты и зависимости — обычно мало, но кривая компиляция .NET-библиотек может удивлять.

После сборки Unity пишет Build Report в Editor.log (~/Library/Logs/Unity/Editor.log на macOS, %LOCALAPPDATA%\Unity\Editor\Editor.log на Windows) с разбивкой “что сколько весит”. Удобнее смотреть через сторонний инструмент Build Report Inspector или через сами файлы билда (.unity3d, ассет-бандлы) — но Editor.log даёт минимально работоспособный обзор.

LOD (Level Of Detail)

LOD Group — компонент, в котором у одного объекта несколько уровней детализации (LOD0 — high, LOD1 — middle, LOD2 — low, Culled — невидимо). Камера выбирает уровень по экранному размеру объекта. Бесплатные FPS, особенно в больших открытых сценах.

Окклюзия и culling

  • Frustum Culling — объекты вне поля зрения не рендерятся. Включено всегда.
  • Occlusion Culling — объекты, скрытые за другими (стенами), не рендерятся. Нужно запекать (Window → Rendering → Occlusion Culling), требует Occluder Static / Occludee Static флаги.
  • Layer Culling Distance — на Camera можно задать, что объекты определённого слоя рендерятся только до X метров (травинки исчезают на 30м, деревья — на 200м).

WebGL / WebGPU

Если цель — браузер:

  • Только IL2CPP, только AOT.
  • Нет потоков по умолчанию (есть Threads experimental с COOP/COEP-заголовками на хостинге).
  • Большой initial download (десятки мегабайт). Используйте Brotli compression.
  • Audio с ограничениями (AudioContext autoplay policies).
  • WebGPU backend — публично доступен с Unity 6.1 (март 2025). На май 2026 поддерживается всеми основными браузерами (Chrome, Firefox с июля 2025, Safari 26 с сентября 2025). Даёт compute shaders, лучшую производительность, поддерживает Forward+. Важно: в Unity Manual 6.x WebGPU всё ещё помечен как experimental, не для production. Для прототипов и dev-сборок — отличный выбор; для shipping — оценивайте риски и оставляйте WebGL2-fallback.

Чек-лист релиза

  • Профайлер показывает стабильные 60 FPS на target-устройстве в репрезентативной сцене.
  • GC Alloc в Update ≈ 0 в нормальном gameplay.
  • Draw calls < разумного предела для платформы (мобайл — < 200, PC — < 1000 при средней сцене).
  • Текстуры сжаты, не сырая PNG/TGA в импорте.
  • LOD на тяжёлых моделях.
  • Occlusion culling запечена для интерьеров.
  • Player Settings: версия игры, иконка, splash, certificates (для подписи).
  • Билд протестирован на целевом устройстве, не только на dev-машине.
  • Logging выключен в release (через #if DEBUG или Log Strip Level).

В следующем (заключительном) разделе — короткий глоссарий: термины Unity и их веб-аналоги.