Skip to content
E
Egmatic
медленная сборка игрыоптимизация времени сборкивремя сборки IL2CPPотсечение вариантов шейдеровконвейер разработки игр

Как ускорить сборку игры: 8 проверенных способов оптимизации

Медленная сборка игры — не загадка. Это конвейер с несколькими дорогими этапами, и рецепт всегда один: сначала измерить, а потом бить по тому этапу, который реально тормозит. Обычно виноваты импорт и обработка ассетов, генерация C++ через IL2CPP в Unity, компиляция вариантов шейдеров и полные пересборки из-за холодного кэша. В руководстве — восемь приёмов, которые работают в Unity, Godot, MonoGame и GameMaker: держите кэш сборки прогретым, используйте инкрементальные сборки IL2CPP, отсекайте лишние варианты шейдеров, включайте параллельную компиляцию и подбирайте конфигурацию под задачу. Без выдуманных процентов: измеряйте свой результат до и после с помощью отчёта о сборке или бинарного журнала MSBuild.

Vladislav Kovnerov28 июля 2026 г.12 мин

Медленная сборка игры — не загадка. Сборка — это конвейер из нескольких этапов, и почти каждая тормозящая сборка медленная из-за одного из четырёх: импорт и обработка ассетов, генерация C++ через IL2CPP в Unity, компиляция вариантов шейдеров или холодный кэш, вызывающий полную пересборку. Рецепт всегда один и тот же, в два шага: измерить, какой этап реально тормозит, а потом бить по нему. Это руководство — восемь рабочих приёмов и объяснение, почему никто не может назвать вам процент ускорения для вашего проекта.

Сразу предупреждение: почти каждая встречающаяся в сети цифра «этот приём ускоряет сборку на X процентов» выдумана. Unity, Microsoft и Godot документируют свои системы сборки, но не публикуют итоговых процентов — результат слишком сильно зависит от проекта. Единственная честная цифра — измеренная вами лично. Поэтому первый приём — тот, что делает остальные семь осмысленными.

Четыре причины медленной сборки

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

ЭтапЧто происходитПочему медленно
Импорт ассетовТекстуры сжимаются, звук кодируется, модели обрабатываются и кэшируются в бинарном видеСжатие и кодирование нагружают процессор; пустой кэш заставляет делать всё заново
Компиляция скриптовC# (или C++) компилируется под целевую среду выполненияIL2CPP добавляет шаг генерации и компиляции C++, которого у Mono нет
Компиляция шейдеровКаждый вариант шейдера компилируется под каждый графический APIВарианты размножаются комбинаторно — n ключевых слов могут дать до 2^n вариантов
УпаковкаСобранное содержимое пакуется в формат платформы (APK, AAB, исполняемый файл)Каждая дополнительная платформа добавляет свой проход

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

Теперь — приёмы.

1. Сначала измеряйте — всегда

Если вы не знаете, какой этап тормозит, вы будете оптимизировать не то. У каждой крупной сборочной цепочки есть способ прочитать разбивку времени по этапам — пользуйтесь им до любых изменений.

  • Unity: API BuildReport показывает, что собрано и какого размера каждый блок, а файл Editor.log содержит время по шагам — именно там видно, куда уходят минуты. Пакет Build Report Inspector визуализирует отчёт.
  • .NET / MonoGame / MSBuild: выполните dotnet build -bl, чтобы получить бинарный журнал, затем откройте msbuild.binlog в средстве просмотра Structured Log Viewer. Он показывает время по проектам и задачам — это лучший способ найти медленный проект в решении.
  • Godot: запуск с --verbose выводит активность импорта, а статус кэша .godot/imported/ виден в редакторе.

Запишите время «до», поменяйте одну вещь, запишите «после». Без этого — гадание.

2. Держите кэш сборки прогретым

Самая частая причина внезапно медленной сборки — холодный кэш. Unity хранит импортированные ассеты в Library/; Godot — в .godot/imported/; MSBuild и MGCB держат промежуточные объектные файлы между сборками. Удалите любой из них — и следующая сборка повторно импортирует и скомпилирует всё.

Рецепт здесь — привычка, а не настройка: не удаляйте каталог кэша между сборками. Если в CI есть шаг «чистой» сборки, убедитесь, что он чистит только необходимое. Если команда делит работу по импорту, поднимите кэш-сервер — в Unity это Unity Accelerator, наследник прежнего отдельного Cache Server, — чтобы импорт одного разработчика переиспользовали остальные.

Конвейер импорта ассетов версии 2 (Asset Import Pipeline v2) стал по умолчанию в Unity начиная с 2020.1 и заметно быстрее прежнего, а помимо этого выигрывает от Accelerator. Если вы на старой версии Unity с конвейером v1, переход на v2 — изменение с самой высокой отдачей, которое вы можете сделать.

3. Используйте инкрементальные сборки IL2CPP

IL2CPP — система Unity, превращающая управляемый C# в C++, — это то, из-за чего мобильная или консольная сборка в Unity может занимать во много раз больше времени, чем десктопная на Mono. Заодно это та часть, которую выгоднее всего правильно настроить.

Unity поддерживает инкрементальные сборки IL2CPP: если сохранять выходной каталог IL2CPP (папки Library/il2cpp_*) между сборками, компилятор C++ перекомпилирует только изменившиеся файлы, а не весь сгенерированный код целиком. В официальном руководстве по оптимизации времени сборки IL2CPP эти настройки разобраны. Включайте их для любой платформы, где вы собираетесь повторно.

Более широкое правило: оставляйте IL2CPP для тех сборок, где он окупает свою цену. IL2CPP даёт более высокую производительность на выполнении и бинарники, которые труднее реверсировать, поэтому и стал стандартом для мобильных и консольных релизов. Для быстрой итерации в десктопной отладочной сборке переключите бэкенд сценариев на Mono и пропустите шаг C++ целиком.

4. Отсекайте варианты шейдеров

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

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

В Unity есть два способа урезать число вариантов. В Graphics Settings есть автоматические настройки отсечения, а API IPreprocessShaders и IPreprocessBuild позволяют отсекать варианты программно на этапе подготовки сборки. Отсеките неиспользуемые — и время сборки, и объём памяти на выполнении улучшатся. Та же логика действует в Godot и Unreal: пересчитайте варианты и уберите неиспользуемые.

Это прямой аналог руководства по производительности Blueprint: в любом движке самый быстрый код — тот, который вы никогда не компилируете.

5. Включайте параллельную компиляцию

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

В .NET, MonoGame и любой цепочке на MSBuild передавайте -m (или -maxcpucount), чтобы собирать проекты параллельно на ядрах процессора. В MSBuild 18.6 также появилась поддержка многопоточных сборок внутри процесса. Если в вашем решении много проектов, разница между последовательной и параллельной компиляцией велика, а бинарный журнал из первого приёма точно покажет, сколько проектов собирается и параллелятся ли они.

В Unity редактор компилирует скрипты и импортирует ассеты с внутренним параллелизмом, который обычно не настраивается напрямую; настраивать здесь нужно то, что описано выше (кэш, IL2CPP, шейдеры), а не флаг сборки.

6. Используйте инкрементальные сборки контента

Если ваш движок рассматривает контент (уровни, звук, текстуры) как нечто, что он собирает отдельно от кода, проследите, чтобы пересобиралось только изменившееся.

  • Unity Addressables и Asset Bundles поддерживают инкрементальные сборки контента — пересобираются только изменившиеся бандлы, а не весь набор на каждой сборке игрока. Учтите: отчёт о сборке Addressables отключён по умолчанию именно потому, что его генерация отнимает время; оставьте его выключенным, если только не диагностируете проблему.
  • MGCB (MonoGame Content Builder) задуман так, чтобы пересобирать только изменившиеся ассеты по временным меткам файлов, превращая исходные ассеты в рантайм-файлы .xnb. Он запускается как часть dotnet build. В прошлом встречались баги с полной пересборкой; если подозреваете такое, бинарный журнал MSBuild покажет, что MGCB обрабатывает ассеты, которые должен был пропустить.

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

7. Подбирайте конфигурацию под назначение

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

  • Во время разработки: используйте конфигурацию Debug (или аналог в вашем движке) и самый быстрый бэкенд сценариев. В Unity это Mono. Такие конфигурации пропускают проходы оптимизатора и выдают сборки, рассчитанные на быструю итерацию. В MonoGame/.NET конфигурация Debug выдаёт неоптимизированные сборки с отладочными символами.
  • Для релиза: переключайтесь на Release, включайте IL2CPP или AOT там, где этого требует платформа, и миритесь с более долгим временем сборки, потому что теперь важнее скорость выполнения и размер бинарника.

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

8. Держите сборку на быстром накопителе

Самое прозаичное. Сборка сильно завязана на ввод-вывод — тысячи мелких чтений и записей файлов. Сборка, занимающая много минут на жёстком диске, может ускориться в разы на NVMe SSD. Это нельзя исправить настройкой — это свойство размещения вашего проекта и выходных файлов. Если каталог сборки находится на медленном томе, перенесите его. Ни один движок не документирует конкретного ускорения — результат зависит от диска, — но направление тут единое для всех инженеров.

Краткая справка по движкам

ДвижокСамые выигрышные шаги
UnityКонвейер импорта v2 + Accelerator, инкрементальный IL2CPP, отсечение вариантов шейдеров, Mono для разработки
Godot 4Сохраняйте .godot/imported/, многопоточный импорт, --verbose для диагностики
MonoGame / .NETdotnet build -m для параллелизма, -bl для диагностики, инкрементальные контентные сборки MGCB, держите кэш
GameMakerДля быстрой итерации используйте цель VM (не YYC), YYC оставьте для релиза

Роль Egmatic

Egmatic — это IDE для 2D-игр на базе MonoGame, и её история сборки — это история MonoGame/.NET: dotnet build с инкрементальной компиляцией, контентный конвейер MGCB для ассетов и стандартные параллелизм и бинарные журналы MSBuild. Что Egmatic меняет — цикл итерации до сборки: живой предпросмотр означает, что большую часть вопросов «правильно ли это ощущается» вообще не нужно закрывать сборкой. Меньше нужных сборок — меньше медленных сборок, которые приходится ждать, а это самый дешёвый вид оптимизации. Когда сборка всё-таки нужна, перечисленные приёмы действуют без изменений.

Частые ошибки

  • Оптимизация до измерения. Если вы не знаете, какой этап тормозит, почините не то. Начинайте всегда с отчёта о сборке или бинарного журнала.
  • Очистка кэша между сборками. Холодный кэш — самая частая причина медленной сборки. Перестаньте удалять Library/ или .godot/ по привычке.
  • IL2CPP для каждой сборки. IL2CPP нужен для релиза и для платформ, которые его требуют. Для отладочной итерации Mono быстрее.
  • Игнорирование вариантов шейдеров. Их число растёт комбинаторно. Пара ключевых слов multi_compile может незаметно добавить тысячи единиц компиляции.
  • Сборка под все платформы сразу. Каждая лишняя цель добавляет полный проход упаковки. Собирайте под ту платформу, на которой тестируете.
  • Последовательные сборки. Если ваша цепочка поддерживает параллельную компиляцию, а у вас есть ядра, — используйте их.

Когда это применимо

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