Ошибки сборки игры: быстрые решения для проблем, которые действительно ломают сборку
Ошибка сборки — это сбой компиляции или упаковки, из-за которого игра вообще не собирается в запускаемый артефакт. Её отличие от бага времени выполнения в том, что баг проявляется только во время игры, а ошибка сборки не даёт даже запустить проект. Большинство ошибок сборки укладываются в несколько категорий: отсутствующие сцены или ассеты, код, рассчитанный только на редактор и не существующий в релизной сборке, неверные настройки платформы или SDK, повреждённый кэш и несовпадение версий зависимостей. В руководстве — повторяющиеся ошибки сборки в Unity, Godot, MonoGame и GameMaker, метод диагностики для любого движка, шаги чистой пересборки для каждой платформы и способы предотвращения сбоев. Никаких выдуманных процентов: читайте собственный лог сборки и чините то, что в нём указано.
Ошибка сборки игры — это сбой компиляции или упаковки, из-за которого проект не удаётся собрать в запускаемую сборку. Это не то же самое, что баг времени выполнения, который проявляется только в процессе игры. Практическая разница существенна: ошибка сборки не даёт даже получить то, во что можно поиграть, а лог сборки обычно сам называет файл и строку с причиной. В этом руководстве — ошибки сборки, которые регулярно возникают в Unity, Godot, MonoGame и GameMaker, метод диагностики, работающий в любом из них, и шаги чистой пересборки для каждой платформы. Главное правило звучит просто: читайте лог сборки, находите первую ошибку и чините сначала её — первая ошибка почти всегда и есть настоящая причина, а всё остальное часто лишь её последствия.
Честное замечание перед разбором: почти каждый рейтинг «эта ошибка отвечает за столько-то процентов сбоев», который встречается в сети, выдуман. Движки документируют, как работают их системы сборки, но никто не публикует надёжных данных о том, какая ошибка встречается чаще, — это полностью зависит от проекта, команды и целевых платформ. Приведённые ниже категории реальны и повторяются; любые точные проценты рядом с ними стоит воспринимать с подозрением.
Ошибка сборки против бага времени выполнения
Самое полезное различие — на каком этапе происходит сбой.
| Ошибка сборки | Баг времени выполнения | |
|---|---|---|
| Когда возникает | При компиляции или упаковке | Во время работы игры |
| Результат | Запускаемая сборка не создаётся | Сборка работает, но ведёт себя неправильно |
| Как находят | Лог сборки называет файл и строку | Воспроизводят, играя в игру |
| Типичная причина | Код, который не компилируется, отсутствующие ассеты, неверные настройки | Логика, которая компилируется, но неверна в игре |
Ошибки сборки кажутся страшнее, потому что блокируют всё, но обычно это более простой класс неисправностей: система сборки уже проделала за вас работу по поиску места. Баги времени выполнения компилируются без проблем и прячутся, пока кто-нибудь не доиграет до них.
Пять повторяющихся категорий
В любом движке ошибки сборки, которые её останавливают, укладываются в небольшое число групп.
| Категория | Как выглядит | Где бьёт сильнее всего |
|---|---|---|
| Отсутствующие ссылки или ассеты | «Сцена не в сборке», «файл не найден», неразрешённый символ | Unity, Godot |
| Код только для редактора | Вызовы API редактора, которых нет в релизной сборке | Unity, Godot |
| Несовпадение платформы или SDK | Неверная цель, отсутствующие шаблоны экспорта, устаревший SDK | Везде, особенно мобильные и консоли |
| Повреждённый кэш | Необъяснимые ошибки, исчезающие после чистой пересборки | Везде |
| Несовпадение версий зависимостей | Плагин под старую версию движка, несовпадение NuGet/SDK | Везде |
Остальная часть руководства — метод диагностики, а затем конкретные способы лечения по каждой категории.
Метод диагностики (работает в любом движке)
Прежде что-либо менять, действуйте в таком порядке:
- Прочитайте лог сборки и найдите первую ошибку. Не последнюю — именно первую. Компиляторы выдают десятки ошибок, которые идут следом за одной первопричиной, и устранение первопричины убирает бо́льшую часть остальных.
- Отнесите её к одной из пяти категорий выше. Категория подсказывает, где искать.
- Воспроизведите ошибку изолированно, если получится, — свежий проект только с проблемным фрагментом исключает влияние остального кода.
- Пробуйте чистую пересборку только после того, как поняли ошибку. Чистая пересборка — инструмент грубый: она лечит повреждённый кэш, но скрывает настоящую причину большинства других ошибок, и если почистить первым делом, разгадка теряется.
Лечение по категориям
1. Отсутствующие ссылки и ассеты
Классический случай — игра отлично работает в редакторе, а потом не собирается, потому что сборке неизвестна сцена или ассет, которые были загружены в редакторе.
- Unity: откройте File → Build Settings и убедитесь, что каждая нужная сцена есть в списке Scenes In Build. Сцена, на которую ссылается код, но которой нет в этом списке, — самая частая причина ситуации «работает в редакторе, не собирается в сборку».
- Godot: проверьте, что ресурсы сохранены и что фильтры ресурсов в пресете экспорта их включают. Несохранённый или отфильтрованный ресурс доступен в редакторе, но не попадает в экспорт.
- MonoGame / .NET: ошибка «неразрешено» или «не найдено» обычно означает, что в коде есть
usingдля пакета, на который нет ссылки, либо путь к ассету не совпадает с тем, что выдал конвейер контента.
2. Код только для редактора
Редакторы предоставляют API, существующие только в редакторе. Код, который их вызывает, компилируется во время работы в редакторе, а затем ломает релизную сборку, потому что из релизных сборок эти API вырезаются.
- Unity: всё, что относится к пространству имён
UnityEditor, не должно попадать в код, который уходит в релиз. Оберните его в#if UNITY_EDITOR…#endif, чтобы при сборке он исключался, либо перенесите в сборку, предназначенную только для редактора. - Godot: держите инструменты и плагины редактора вне кода, который идёт на экспорт. Плагины редактора работают только внутри редактора.
- MonoGame: утечь некуда, потому что в самом MonoGame редактора нет, — но тот же принцип касается любого платформенно-условного кода (
#if WINDOWS,#if ANDROID).
3. Несовпадение платформы и SDK
Сборки под мобильные устройства и консоли ломаются здесь чаще всего.
- Целевая платформа: убедитесь, что цель сборки совпадает с устройством или магазином, под который вы собираете. Сборка не под ту архитектуру или версию ОС — частая и незаметная неудача.
- Шаблоны экспорта Godot: экспорт падает с ошибкой шаблона, когда установленные шаблоны отсутствуют или не совпадают с версией редактора. Установите подходящие шаблоны из диалога Export в редакторе.
- Версии SDK: для мобильных платформ держите SDK и инструменты сборки актуальными — магазины со временем повышают требуемый уровень API, и слишком старый уровень сам по себе становится причиной отказа. Для консолей SDK выдаёт владелец платформы по NDA.
4. Повреждённый кэш
Некоторые ошибки не имеют логического объяснения: ассет, который нормально импортировался вчера, вдруг падает, или сборка ломается на одной машине, но не на другой. Причина — повреждённый промежуточный кэш, а лекарство — чистая пересборка (следующий раздел). Это единственная категория, где чистка первым делом оправдана, потому что реального бага тут читать неоткуда.
5. Несовпадение версий зависимостей
- Сторонние плагины: плагин, собранный под старую версию движка, часто ломает сборку после обновления. Обновляйте каждый плагин до версии под ваш текущий движок.
- MonoGame / .NET: пакет NuGet или SDK для .NET, не совпадающий с целевым фреймворком проекта, не восстанавливается и не компилируется. Держите версии SDK и пакетов согласованными с тем, на что рассчитан проект.
Чистая пересборка по движкам
Когда ошибка — повреждённый кэш или вы уже исключили всё остальное, лечением становится чистая пересборка. Всегда работайте с проектом, у которого есть резервная копия.
| Движок | Что удалить или выполнить | Примечания |
|---|---|---|
| Unity | Удалите папки Library и Temp | Приводит к полному реимпорту; следующая сборка медленнее |
| Godot | Удалите .godot/imported (или всю папку .godot) | При следующем открытии реимпорт всех ассетов |
| MonoGame / .NET | dotnet clean либо удалите bin и obj | Перекомпиляция с нуля |
| GameMaker | Clean Build в меню сборки или очистка кэша в настройках | Удаляет закэшированный вывод компиляции |
| Unreal | Удалите папки Binaries, Intermediate и Saved | Тяжёлая операция; после неё перегенерируйте файлы проекта |
Там, где у движка есть штатная команда очистки, предпочтительнее она: ручное удаление папок работает, но пропускает служебные действия, которые выполнила бы команда.
Как предотвратить ошибки сборки
Профилактика обходится дешевле, чем разбор ошибок, и большей частью относится к процессу, а не к инструментам.
- Собирайте рано и часто. Чем дольше между успешными сборками, тем больше набор изменений, любое из которых могло что-то сломать. Сборка, которая запускается при каждом сохранении, ловит ошибки, пока их причина ещё свежа.
- В CI относитесь к предупреждениям как к ошибкам. Если непрерывная сборка падает на предупреждениях, «починю потом» превращается в «чиню сейчас». Для здоровья сборки в команде это изменение с самой большой отдачей.
- Зафиксируйте инструментарий. Закрепите версию движка, SDK для .NET и версии плагинов в системе контроля версий или в документированной настройке. Расхождение между машинами разработчиков — тихая и постоянная причина «у меня собирается».
- Разделяйте код для редактора и для рантайма. Держите всё, что не должно попадать в релиз, в чётко выделенных, условно компилируемых частях или в сборках только для редактора, чтобы это не просочилось в релизную сборку.
- Держите кэш сборки тёплым. Холодный кэш вызывает полную пересборку — она медленнее, а заодно это момент, когда кэш пересоздаётся и иногда портится. С тёплым стабильным кэшем сборка проходит быстрее и с меньшим числом сбоев.
Если проблема не в том, что сборки ломаются, а в том, что они медленные, — это другой вопрос с другим набором ответов, см. руководство по ускорению сборки.
Роль Egmatic
Egmatic — это IDE и движок для 2D-игр на базе MonoGame, и история со сборкой — одна из причин, почему это важно. Чистый проект на MonoGame компилируется стандартным инструментарием .NET — dotnet build, MSBuild, обычная компиляция C#, — поэтому ошибки сборки в Egmatic — это обычные ошибки компиляции C# и сообщения конвейера контента, а не непрозрачные внутренности движка. Здесь нет шага IL2CPP, превращающего C# в C++ и компилирующего уже его, нет пространства имён редактора, которое может просочиться в релиз, и нет скрытого слоя движка между вами и логом сборки. Если что-то падает, лог говорит, что и где.
Две вещи в рабочем процессе снижают число ошибок сборки ещё до того, как они возникнут. Конвейер контента (MGCB) обрабатывает ассеты во время сборки и сообщает об отсутствующих или некорректных ассетах как об именованных ошибках, а не как о тихих пропусках. А предпросмотр в реальном времени позволяет запустить игру внутри редактора без полной сборки, так что значительная часть ошибок, которые иначе всплыли бы при сборке, ловится раньше, пока вы ещё редактируете. Сама сборка становится последним шагом, а не первым моментом, когда вы узнаёте, работает ли игра.
Полный разбор первой сборки на MonoGame с нуля — установка, создание проекта, игровой цикл и команды — есть в пошаговом руководстве, а обзор того, что такое MonoGame, объясняет фундамент, в который компилируется Egmatic.