Почему структура папок имеет значение

Как консультант в команде Customer Success, я часто получаю вопрос "Правильно ли мы создали наши пакеты активов?" или его разновидность. Мой ответ всегда один и тот же: Это зависит от проекта. Затем я общаюсь с клиентами по поводу конкретики. Хотя этот ответ и является точным, он не дает никакой информации для будущих проектов.
Хотя эта дилемма встречается довольно часто, мне трудно найти более общий ответ на этот вопрос (несмотря на существующие рекомендации и лучшие практики для Addressables). Некоторые пользователи не знают, правильны ли связки для начала, а мое время часто ограничивается проверкой проектов на предмет оптимизации памяти. Это означает, что я не могу определить предназначение каждого актива в проекте. Кроме того, по мере расширения проекта может оказаться невозможным, чтобы один человек отвечал на один и тот же вопрос по каждому активу.
В конце концов меня осенило: Вопрос о правильном построении пучков активов ограничивает перспективу поиска более общего ответа. Позвольте мне объяснить.
Пакет активов занимает память при загрузке, поэтому, если активы объединены с другими активами, которые не загружаются и не выгружаются одновременно, вы используете память не так оптимально, как могли бы. Поэтому вопрос о том, находится ли актив в правильной связке или есть ли в связке правильные активы, по сути, является вопросом о том, загружаете ли вы правильные активы в правильное время. Ответ на вопрос, когда следует загружать конкретные активы, зависит от их предполагаемого использования, поэтому обычно говорят: "Это зависит от проекта". На практике я обнаружил, что изучение предполагаемого использования актива позволяет понять, как он загружается в память и как его следует компоновать.
Итак, "предполагаемое использование" - это ключевая фраза: Кто знает, как предполагается использовать тот или иной актив? Как донести это намерение до всех? И, наконец, когда это должно произойти?
На мой взгляд, есть один момент, когда ответ на этот вопрос предельно ясен: при создании и изменении актива. Будь то конкретная текстура для персонажа, шейдер глобального освещения или сетка деревьев для использования в нескольких уровнях игры, создатель знает, для чего она предназначена, и, следовательно, он лучше всех сможет передать это намерение. Художники могут передать это намерение, применяя единые правила именования файлов и группируя файлы с одинаковым назначением в одной папке.
Программисты и другие члены команды могут использовать эту информацию, чтобы решить, когда и нужно ли объединять актив с другими активами, которые будут загружаться одновременно. В связи с этим предполагаемое использование актива должно быть предельно ясным - с первого взгляда - на протяжении всего проекта, а каталог файлов выступает в качестве источника истины для всех членов команды.
В этой статье я рассмотрю некоторые лучшие практики и распространенные крайние случаи, которые, надеюсь, помогут вам лучше структурировать будущие проекты. Сначала обсудим некоторые распространенные структуры папок и их проблемы.
По моему опыту, существует четыре типа структуры папок: случайная, по типу активов, по характеристикам и по назначению. Из них последний - самый лучший, потому что он передает замысел и, следовательно, наиболее подходит для оптимальной стратегии пакетирования.
Случайность - это не тот случай, который я часто встречаю. В основном это происходит с разработчиками-одиночками, которые могут быть незнакомы с разработкой программного обеспечения. По понятным причинам это становится невозможным, когда проект увеличивается в размере или усложняется. Отсутствие структуры или беспорядочная структура влечет за собой множество проблем - активы трудно найти, а понять их назначение практически невозможно.
Структурирование по типам активов - довольно распространенное явление, поскольку именно так многие художники работают с активами перед их импортом в движок. Если вы знаете тип актива, найти его местоположение не составит труда, но все остальное о нем будет непонятно. Даже при наличии отличного соглашения о наименованиях бывает сложно определить, требуется ли персонажу, окружению, пользовательскому интерфейсу или любой комбинации из этих трех элементов определенный шейдер, текстура, сетка и т. д. Соответствующий каталог файлов должен не скрывать информацию, а раскрывать ее.
Структуры папок по признакам встречаются редко, но на первый взгляд кажутся разумными. Многие компании делятся на группы по функциям, так почему бы не сгруппировать данные аналогичным образом? Игра использует данные не так. В прошлом я видел примеры, например, шейдеров и аудио, которые должны быть объединены, но из-за того, что их авторами являются разные команды, эта истина становится непонятной.
Каталог файлов с четким соглашением об именовании, обусловленным назначением активов, позволяет обойти эти проблемы. Чтобы проиллюстрировать это, я использую пример вымышленной игры под названием "Dinosaur Brawl".
В данном примере Dinosaur Brawl - это приключенческая 3D-игра от третьего лица, в которой игрок выбирает одного динозавра, чтобы управлять им в огромном открытом мире с множеством биомов, сражаясь с другими динозаврами и доисторическими существами в попытке стать сильнее и передать свои гены следующему поколению - и все это в гигантской борьбе за выживание в грядущем ледниковом периоде. Игра предназначена для мобильных устройств, и часть данных будет распространяться как часть оригинального приложения. Остальное будет загружаться с CDN по мере необходимости.
На основе приведенного выше описания мы можем разработать общую структуру папок для всего проекта. Поскольку игрок может выбирать и сражаться с другими динозаврами, имеет смысл создать для каждого динозавра папку, в которой будут храниться все активы, относящиеся к этому динозавру: сетки, звуковые эффекты, текстуры, анимации, эффекты частиц и т. д. Я отнесу их к категории "Уникальные активы".
Так как это экшен, в игре будет окружение, представляющее собой отдельные биомы. Поэтому мы должны создать отдельную папку для каждого биома, или уровня, в проекте: равнины, пустыни, тундра, болота, вулканы и т. д.
Конечно, будут и такие активы, присутствие которых необходимо для прохождения целых частей игры. Одним из таких наборов являются элементы пользовательского интерфейса. Вы можете считать эти активы глобальными активами. Точно так же, как мы создали одну папку для всех уникальных активов, должна быть и глобальная папка, которая находится на вершине иерархии папок. Например, папка Global UI, папка Global Dinosaur, папка Global Environment и так далее. Таким образом, все вещи, общие для этих игровых разделов, хранятся в одном месте.
Эта категория активов определяется как общая для некоторых уникальных активов, но не для всех. Поэтому они не относятся ни к категории глобальных, ни к категории уникальных активов. Для Dinosaur Brawl примером такого типа общих ресурсов могут быть те, которые присутствуют во всех летающих динозаврах, например частицы, шейдеры и звуковые эффекты, необходимые для создания ощущения парения в воздухе.
Часто случается так, что эти активы попадают в папку первого динозавра, которому они нужны. К сожалению, это не совсем точно описывает, как они должны использоваться, и, следовательно, искажает их смысл. В худшем случае активы будут дублироваться в каждом пакете с летающими динозаврами, что неэффективно с точки зрения памяти, отладки и размера приложения.
Лучшее решение - создать новую папку с именем, указывающим на ее предназначение, например Flying Dinosaurs. С определением местоположения дело обстоит сложнее: стандарта не существует. Я предпочитаю помещать их в подпапку на том же уровне, что и глобальные и уникальные папки с динозаврами, но их можно поместить и в другие папки Unique.
Типичный случай, когда требования проекта меняются, и актив, который изначально должен был быть уникальным, становится общим. В нашем примере Dinosaur Brawl, чтобы сэкономить время разработки, было принято решение использовать префаб Velociraptor в качестве основы для всех остальных рапторов (таких как Utahraaptor, Dokataraptor и т. д.).
Однако разработчики не понимают, что при добавлении префаба Velociraptor в пакет все активы Velociraptor будут загружаться при загрузке всех остальных хищников, что увеличивает время загрузки, несмотря на использование только префаба.
Это произошло потому, что назначение актива было изменено, и структура папок перестала его отражать. При изменении намерений местоположение и название актива(ов) должны быть обновлены, чтобы сохранить последовательность и точность в системе. Это дает команде, создающей пакеты, понять, какие активы должны быть в пакете "Shared Raptor", а какие должны остаться в уникальной модели Velociraptor.
Один из самых распространенных и трудноисправимых случаев - когда актив непреднамеренно используется не по назначению. Когда такое случается, это, как правило, несчастный случай. Например, кому-то нужно уложиться в срок, и он использует уже существующий актив в проекте, чтобы быстро завершить работу.
Возьмем такой сценарий: Художник добавляет туториал для грядущего расширения Dinosaur Brawl и находит шейдер "золотого свечения", чтобы подчеркнуть, когда игроки могут провести контратаку на элитных врагов. Художник не знает, что этот шейдер - контент для конечной игры против огромного Ти-Рекса - это уникальный босс, в котором собрано множество активов. Теперь все эти активы будут загружены во время обучения, в том месте, где большинство активов не используется. Этот пакет огромен, поэтому система, которая обычно загружает такие мелкие активы в середине игры, испытывает нагрузку, что приводит к разным последствиям - от скачков производительности до сбоев из-за того, что актив не может быть загружен достаточно быстро игроками с плохим соединением.
Это крайний, но вполне реалистичный пример, который я видел в нескольких проектах. Именно поэтому, помимо структуры папок, у всех активов должно быть имя, которое передает их назначение. Если бы шейдер назывался, например, gold_glow_trex_endgame, было бы понятно, для чего он предназначен. Тогда при отладке будет очевидно, что этот актив не должен загружаться во время обучения.
Если вы знакомы с Addressables, то, возможно, знаете, что Groups и Labels используются для группировки и маркировки активов примерно так же, как я предлагал в примере с игрой выше - с помощью папок и разумных соглашений об именовании. Вы можете задаться вопросом: "Зачем возиться со всем этим, если можно сделать это с помощью групп и меток?".
Мой ответ: нужно делать и то, и другое. Как я уже объяснял в самом начале, с ростом количества активов в проекте одному человеку становится все труднее и труднее понять, как все активы должны быть использованы. Знание того, что Addressables Groups должны соответствовать структуре папок, можно использовать как способ подтверждения правильности их настройки.
Я видел, как многие наши клиенты, использующие пакеты активов без Addressables, кодируют сложные системы в качестве решения этой проблемы. Например, они будут создавать и поддерживать мастер-лист, который используется для создания пакетов, или проверять коммиты в системе контроля версий для сравнения изменений в пакетах и т. д. Мой опыт показывает, что такие решения не являются экономически эффективными в долгосрочной перспективе. Это еще одна система, которую нужно разрабатывать и поддерживать, что создает дополнительные точки отказа. По мере масштабирования проекта они прогибаются под множеством исключений и крайних случаев, которые естественным образом накапливаются у долгоживущих проектов. Хуже всего то, что на фундаментальном уровне они не работают, потому что в них нет средств защиты от ошибок пользователей.
Четко структурированная система папок и соглашение об именовании файлов должны приводить к совпадению 1 к 1 для пакетов активов и групп Addressables. Распределение файлов по логическим группам и подпапкам гарантирует, что все члены команды будут одинаково интерпретировать и находить файлы, уменьшая вероятность недоразумений и расхождений при смене персонала и изменении требований проекта. Создатели активов могут облегчить доступ к ним и навигацию, избавив других членов команды от необходимости тратить время на поиск конкретных активов. Системный подход экономит драгоценное время и сводит к минимуму вероятность ошибок и упущений. Становится постоянным ориентиром, источником истины, облегчает процесс вхождения в команду новых членов и обеспечивает жизнеспособность проекта в течение долгого времени.
Нужна поддержка или совет по структуре папок? Общайтесь с нами на форумах. Ознакомьтесь с другими техническими блогами разработчиков Unity в рамках продолжающейся серии Tech from the Trenches.
