10 самых распространенных ошибок, которые совершают разработчики Unity

Опубликовано: 2022-03-11

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

Unity — отличный и простой инструмент для мультиплатформенной разработки.
Твитнуть

Распространенная ошибка Unity №1: недооценка этапа планирования проекта

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

С более технической точки зрения необходимо заранее установить весь рабочий процесс создания активов и моделей при предоставлении их программисту, уделяя особое внимание процессу итерации, когда модели потребуют дополнительных изменений и уточнений. У вас должно быть четкое представление о желаемой частоте кадров и бюджете вершин, чтобы 3D-художник мог знать, в каком максимальном разрешении должны быть модели и сколько вариаций LOD он должен сделать. Также следует указать, как унифицировать все измерения, чтобы иметь согласованный масштаб, и процесс импорта во всем приложении.

То, как будут спроектированы уровни, имеет решающее значение для будущей работы, потому что разделение уровня сильно влияет на производительность. Вопросы производительности всегда должны быть у вас в голове при разработке новых уровней. Не идите с нереалистичными видениями. Всегда важно задавать себе вопрос: «Может ли это быть разумно достигнуто?» Если нет, вам не следует тратить свои драгоценные ресурсы на что-то труднодостижимое (если, конечно, это не является частью вашей бизнес-стратегии, чтобы сделать это вашим основным конкурентным преимуществом).

Распространенная ошибка Unity №2: работа с неоптимизированными моделями

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

Важно правильно установить масштаб. Иногда это невозможно правильно установить в программном обеспечении для 3D-моделирования из-за разных единиц измерения, используемых этими приложениями. Чтобы все было правильно, установите масштабный коэффициент в настройках импорта моделей (оставьте 0,01 для 3dsMax и Modo, установите 1,0 для Maya), и учтите, что иногда вам потребуется повторно импортировать объекты после изменения настройки масштаба. Эти настройки должны гарантировать, что вы можете использовать только базовый масштаб 1,1,1 в своих сценах, чтобы получить согласованное поведение и отсутствие проблем с физикой. Динамическая пакетная обработка также, скорее всего, будет работать корректно. Это правило также следует применять к каждому подобъекту модели, а не только к основному. Когда вам нужно настроить размеры объекта, делайте это в отношении других объектов в приложении для 3D-моделирования, а не в Unity. Тем не менее, вы можете поэкспериментировать с масштабом в Unity, чтобы найти подходящие значения, но для конечного приложения и последовательного рабочего процесса хорошо все подготовить перед импортом в Unity.

Что касается функциональности объектов и их динамических частей - ваши модели должны быть хорошо разделены. Чем меньше подобъектов, тем лучше. Отдельные части объекта на всякий случай, когда они вам нужны, например, для динамического перемещения или вращения, для целей анимации или других взаимодействий. Каждый объект и его подобъекты должны иметь свою точку опоры, правильно выровненную и повернутую относительно своей основной функции. Главный объект должен иметь ось Z, указывающую вперед, а точка поворота должна быть внизу объекта для лучшего размещения на сцене. Используйте как можно меньше материалов на объектах (подробнее об этом ниже).

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

Распространенная ошибка Unity №3: построение взаимозависимой архитектуры кода

Прототипирование и реализация функционала в Unity довольно проста. Вы можете легко перетаскивать любые ссылки на другие объекты, обращаться к каждому отдельному объекту в сцене и получать доступ к каждому его компоненту. Однако это также может быть потенциально опасным. Помимо заметных проблем с производительностью (поиск объекта в иерархии и доступ к компонентам имеют свои накладные расходы), существует также большая опасность сделать части вашего кода полностью зависимыми друг от друга. Или зависимость от других систем и сценариев, уникальных для вашего приложения, или даже от текущей сцены или текущего сценария. Попробуйте использовать более модульный подход и создавайте повторно используемые части, которые можно использовать в других частях вашего приложения или даже совместно использовать во всем вашем портфолио приложений. Создавайте фреймворк и библиотеки на основе API Unity так же, как вы строите свою базу знаний.

Для этого существует множество различных подходов. Хорошей отправной точкой является сама система компонентов Unity. Сложности могут возникнуть, когда определенным компонентам необходимо взаимодействовать с другими системами приложения. Для этого вы можете использовать интерфейсы, чтобы сделать части вашей системы более абстрактными и повторно используемыми. В качестве альтернативы вы можете использовать подход, управляемый событиями, для реагирования на определенные события извне, либо путем создания системы обмена сообщениями, либо путем регистрации непосредственно в частях другой системы в качестве слушателей. Правильным подходом будет попытка отделить свойства gameObject от логики программы (по крайней мере, что-то вроде принципа модель-контроллер), потому что трудно определить, какие объекты изменяют свои свойства преобразования, такие как положение и вращение. Это должно быть исключительной обязанностью его контроллера.

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

Распространенная ошибка Unity №4: потеря производительности

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

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

Обновление циклов

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

экземпляры

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

Рендеринг

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

Вызовы розыгрыша

Попробуйте уменьшить количество вызовов отрисовки. В Unity вы можете сократить количество вызовов отрисовки, используя статическое пакетирование для неподвижных объектов и динамическое пакетирование для движущихся объектов. Однако сначала необходимо подготовить свои сцены и модели (пакетные объекты должны использовать одни и те же материалы), а пакетная обработка динамических объектов работает только для моделей с низким разрешением. В качестве альтернативы вы можете комбинировать меши с помощью скрипта в один ( Mesh.CombineMeshes ) вместо использования пакетной обработки, но вы должны быть осторожны, чтобы не создавать слишком большие объекты, которые не могут использовать преимущества отбраковки усеченного представления на некоторых платформах. В общем, ключ в том, чтобы использовать как можно меньше материалов и делиться ими со всей сценой. Иногда вам потребуется создавать атласы из текстур, чтобы иметь возможность использовать один материал для разных объектов. Хорошим советом также является использование более высокого разрешения текстур карт освещения сцены (не сгенерированного разрешения, а разрешения вывода текстуры), чтобы уменьшить их количество, когда вы запекаете свет в больших средах.

Проблемы с овердрафтом

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

Шейдеры

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

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

Распространенная ошибка Unity № 5: игнорирование проблем со сборкой мусора

Необходимо понимать, что, несмотря на то, что сборщик мусора (GC) сам по себе помогает нам быть действительно эффективными и сосредоточиться на важных вещах в программировании, есть несколько вещей, о которых мы должны четко знать. Использование GC не бесплатно. Как правило, нам следует избегать ненужного выделения памяти, чтобы сборщик мусора не срабатывал слишком часто и, таким образом, не снижал производительность скачками частоты кадров. В идеале не должно происходить никаких новых выделений памяти, происходящих регулярно в каждом кадре. Однако как мы можем достичь этой цели? Это действительно определяется архитектурой приложения, но есть несколько правил, которым вы можете следовать:

  • Избегайте ненужных выделений в циклах обновления.
  • Используйте структуры для простых контейнеров свойств, поскольку они не размещаются в куче.
  • Попробуйте предварительно выделить массивы, списки или другие наборы объектов, а не создавать их внутри циклов обновления.
  • Избегайте моно проблемных вещей (например, выражений LINQ или циклов foreach), потому что Unity использует более старую, не идеально оптимизированную версию Mono (на момент написания это модифицированная версия 2.6 с обновлением в планах).
  • Кэшировать строки в методах Awake() или в событиях.
  • Если необходимо обновить строковое свойство в цикле обновления, используйте объект StringBuilder вместо строки.
  • Используйте профилировщик для выявления потенциальных проблем.

Распространенная ошибка Unity № 6: оптимизация использования памяти и пространства в последнюю очередь

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

Для поиска поглотителей ресурсов вы можете использовать журнал редактора, где вы можете увидеть (после каждой новой сборки) размер ресурсов, разделенных на отдельные категории, такие как аудио, текстуры и библиотеки DLL. Для лучшей ориентации в Unity Asset Store есть расширения редактора, которые предоставят вам подробную сводку со ссылками на ресурсы и файлы в вашей файловой системе. Фактическое потребление памяти также можно увидеть в профилировщике, но рекомендуется тестировать его при подключении для сборки на вашей целевой платформе, потому что при тестировании в редакторе или на чем-то другом, кроме вашей целевой платформы, возникает много несоответствий.

Чаще всего самыми большими потребителями памяти являются текстуры. Желательно использовать сжатые текстуры, так как они занимают гораздо меньше места и памяти. Сделайте все текстуры квадратными, в идеале сделайте длину обеих сторон степенью двойки (POT), но имейте в виду, что Unity также может автоматически масштабировать текстуры NPOT до POT. Текстуры могут быть сжаты в форме POT. Атласные текстуры вместе, чтобы заполнить всю текстуру. Иногда вы даже можете использовать альфа-канал текстуры для дополнительной информации для ваших шейдеров, чтобы сэкономить дополнительное место и производительность. И, конечно же, старайтесь как можно чаще повторно использовать текстуры для своих сцен и использовать повторяющиеся текстуры, когда это возможно, чтобы сохранить хороший внешний вид. Для младших устройств вы можете понизить разрешение текстур в настройках качества. Используйте сжатый аудиоформат для более длинных аудиоклипов, таких как фоновая музыка.

Когда вы имеете дело с разными платформами, разрешениями или локализациями, вы можете использовать пакеты ресурсов для использования разных наборов текстур для разных устройств или пользователей. Эти пакеты ресурсов можно динамически загружать из Интернета после установки приложения. Таким образом, вы можете превысить ограничение в 100 МБ, загружая ресурсы во время игры.

Распространенная ошибка Unity № 7: распространенные физические ошибки

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

Чтобы изменить положение объекта с Rigidbody на нем, всегда устанавливайте Rigidbody.position , если новая позиция не следует за предыдущей, или Rigidbody.MovePosition , если это непрерывное движение, которое также учитывает интерполяцию. При его изменении применяйте операции всегда в FixedUpdate , а не в функциях Update . Это обеспечит последовательное поведение физики.

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

Распространенная ошибка Unity № 8: ручное тестирование всей функциональности

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

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

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

Распространенная ошибка Unity № 9: Думать, что плагины Unity Asset Store решат все ваши проблемы

Поверьте мне; они не будут. При работе с некоторыми клиентами я иногда сталкивался с тенденцией или пережитками прошлого использования плагинов хранилища активов для каждой мелочи. Я не имею в виду, что в Unity Asset Store нет полезных расширений Unity. Их много, и иногда даже сложно определиться, какой из них выбрать. Но для каждого проекта важно сохранять согласованность, которую можно разрушить неразумным использованием разных частей, плохо сочетающихся друг с другом.

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

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

Распространенная ошибка Unity №10: Отсутствие необходимости расширять базовую функциональность Unity

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

Заключение

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


Дальнейшее чтение в блоге Toptal Engineering:

  • Разработка ИИ в Unity: Учебное пособие по конечному автомату