Префабы (Prefabs)
Довольно удобно работать с GameObject в сцене, добавляя компоненты и изменяя их значения на нужные вам в инспекторе. Однако, это может создать ряд проблем в таких случаях, когда вы работаете над созданием NPC, объектом или предметом, который многократно встречается в сцене. Вы, конечно, можете просто скопировать эти объекты для создания дубликатов, но все они будут редактироваться независимо друг от друга. Обычно вы желаете, чтобы все экземпляры отдельно взятого объекта имели одинаковые значения свойств, чтобы при редактировании одного такого объекта в сцене вам не пришлось повторно вносить те же изменения и во все остальные копии.
К счастью, в Unity можно создавать префабы . Это особый тип ассетов, позволяющий хранить весь GameObject со всеми компонентами и значениями свойств. Префаб выступает в роли шаблона для создания экземпляров хранимого объекта в сцене. Любые изменения в префабе немедленно отражаются и на всех его экземплярах, при этом вы можете переопределять компоненты и настройки для каждого экземпляра в отдельности.
Важно: Когда вы перетаскиваете файловый ассет (например, меш) в сцену, будет создан новый экземпляр такого объекта и все такие экземпляры изменятся при изменении оригинального ассета. Однако, хоть его поведение и похоже, но ассет — это не префаб, так что у вас не выйдет добавить к нему компоненты или использовать любые другие описанные ниже свойства префабов.
Использование префабов
Вы можете создать префаб, выбрав Asset > Create Prefab и перетащив объект со сцены в “пустой” префаб, появившийся в проекте. После чего можно создавать экземпляры префаба просто перетаскивая его из окна Project на сцену. Имена объектов-экземпляров префабы, будут подсвечиваться синим в окне Hierarchy (имена обычных объектов имеют чёрный цвет).
Как уже упоминалось выше, изменения в префабе автоматически применятся ко всем её экземплярам, однако вы можете изменять и отдельные экземпляры. Это полезно например в случае, когда вы желаете создать несколько похожих NPC, но с внешними различиями, чтобы добавить реалистичности. Чтобы было чётко видно, что свойство в экземпляре префаба изменено, оно показывается в инспекторе жирным шрифтом (если к экземпляру префаба добавлен совершенно новый компонент, то все его свойства будут написаны жирным шрифтом).

Также, вы можете создавать экземпляры префабов из кода во время выполнения приложения. Прочтите страницу руководства про создание экземпляров префабов для дополнительной информации.
Редактирование префаба из его экземпляров
Инспектор экземпляра префаба содержит три кнопки, которые у обычных объектов отсутствуют: Select (Выделить), Revert (Отменить) и Apply (Применить).
Кнопка Select выделяет файл префаба, из которого был получен данный экземпляр. Это позволяет быстро найти и отредактировать оригинальный префаб, применяя изменения ко всем его экземплярам. Однако, вы также можете сохранить переопределённые свойства из экземпляра в сам оригинальный префаб с помощью кнопки Apply (изменённые значения положения и вращения трансформации не применяются по очевидным причинам). Это позволяет эффективно редактировать все экземпляры через любой из них, и это быстрый и правильный способ вносить глобальные изменения. Если вы экспериментируете с переопределением свойств, но в итоге решаете, что изначальные свойства (заданные в префабе) для вас предпочтительнее, то вы можете отменить все сделанные переопределения с помощью кнопки Revert, вернув экземпляр в изначальное состояние.
Создание экземпляров префабов во время работы приложения
К данному моменту вы уже должны понимать основы концепта префабов (Prefabs). Префабы — это набор заранее установленных игровых объектов GameObjects и компонентов Components, которые используются более одного раза за всю игру. Если вы не знаете, что такое префаб, то мы рекомендуем вам для начала ознакомиться со страницей Prefabs, для базового объяснения префабов.
Префабы приходятся очень кстати, когда вы хотите создать экземпляры сложных игровых объектов во время игрового процесса. Альтернативой создания экземпляров префабов является создание GameObject с нуля используя код. Создание экземпляра префаба имеет много преимуществ над альтернативным подходом:
- Вы можете создать экземпляр префаба с полным функционалом при помощи одной строчки кода. Создание эквивалентного GameObject из кода в среднем занимает 5 строк кода, а обычно всё же больше.
- Вы можете легко и быстро настраивать, тестировать и модифицировать префабы в сцене и инспекторе.
- Вы можете изменять префаб, экземпляр которого будет создан, без изменения кода, отвечающего за призыв. Простая ракета может быть превращена в супер-заряженную ракету без изменения кода.
Общие сценарии
Чтобы показать мощь префабов, давайте рассмотрим некоторые основные ситуации, где они могут пригодиться:
- Построение стены из одного префаба “кирпича” путём создания его несколько раз в разных позициях.
- Ракетная установка создаёт экземпляр префаба ракеты, когда пользователь жмёт кнопку атаки. Префаб содержит меш, Rigidbody, коллайдер и дочерний GameObject, который содержит систему частиц для следа.
- Робот разлетается на несколько кусков. Полный, функциональный робот уничтожается и заменяется префабом сломанного робота. Этот префаб будет состоять из робота, разделённого на много частей, содержащих Rigidbody и системы частиц. Эта техника позволяет вам взорвать робота на мелкие кусочки просто одной строкой кода, заменяющей один объект на префаб.
Построение стены
Это объяснение иллюстрирует преимущества использования префабов над созданием объектов из кода.
В первую очередь, давайте построим стену из кода:
public class Instantiation : MonoBehaviour < void Start() < for (int y = 0; y < 5; y++) < for (int x = 0; x < 5; x++) < GameObject cube = GameObject.CreatePrimitive(PrimitiveType.Cube); cube.AddComponent(); cube.transform.position = new Vector3(x, y, 0); > > > >
- Чтобы использовать скрипт выше, мы просто сохраняем скрипт и перетягиваем его на пустой GameObject.
- Создайте пустой GameObject при помощи GameObject->Create Empty.
Если вы исполните этот код, вы увидите целую кирпичную стену, создаваемую при входе в режим Play Mode. На отдельный кирпич приходится по 2 строки, отвечающие за функциональность: строки CreatePrimitive() и AddComponent(). Пока что не так и плохо, но все кирпичи не имеют текстур. Каждое дополнительное действие, которое мы хотим сделать с кирпичом, вроде изменения текстуры, трения или массы Rigidbody, требует дополнительную строку.
Если вы создадите префаб и выполните все установки вручную, то вам понадобится использовать лишь по одной строке на создание и установку каждого кирпича. Это освобождает вас от поддержания и изменения тонн кода, когда вы хотите внести изменения. При использовании префаба вы просто вносите изменения в него и жмёте Play. Совсем нет надобности изменять код.
Если вы используете префаб для каждого кирпича, то вот код, который вам понадобится для создания стены.
//Instantiate accepts any component type, because it instantiates the GameObject public Transform brick; void Start() < for (int y = 0; y < 5; y++) < for (int x = 0; x < 5; x++) < Instantiate(brick, new Vector3(x, y, 0), Quaternion.identity); >> >
Он не только очень чистый, но им можно пользоваться много раз. В нём не упоминается ни создание куба, ни то, что он должен содержать Rigidbody. Всё это задано в префабе, который может быть быстро создан в редакторе
Теперь нам остаётся лишь создать префаб, который мы делаем в редакторе. Вот так:
- Выбрать GameObject->Create Other->Cube
- Выбрать Component->Physics->Rigidbody
- Выбрать Assets->Create->Prefab
- В окне Project View измените имя вашего нового префаба на “Brick”
- Перетащите созданный куб в иерархию поверх префаба “Brick” в окно Project View
- Теперь, когда префаб создан, вы можете безопасно удалить куб из иерархии (Delete в Windows, Command-Backspace на Mac)
We’ve created our Brick Prefab, so now we have to attach it to the brick variable in our script. When you select the empty GameObject that contains the script, the Brick variable will be visible in the inspector.
Теперь перетащите префаб “Brick” из окна Project View на переменную brick в инспекторе. Нажмите Play и вы увидите стену построенную из префабов.
Этот шаблон рабочего процесса можно использовать и использовать в Unity. В начале вы, возможно, будете интересоваться, почему же это лучше, чем создание куба из кода, который длиннее лишь на две строки.
Но т.к. вы сейчас используете префаб, вы можете настроить Prefab за секунды. Хотите внести изменения для всей кучи образцов? Настройте Rigidbody в префабе всего один раз. Хотите использовать иной Material для всех образцов? Перетащите материал на префаб всего один раз. Хотите изменить трение? Используйте другой физический материал (Physic Material) в коллайдере префаба. Хотите добавить системы частиц ко всем кирпичам? Добавьте дочернюю систему к префабу всего один раз.
Создание экземпляров ракет и взрывов
Вот как префабы подходят для данного сценария:
- Ракетная установка создаёт экземпляр префаба ракеты, когда пользователь жмёт кнопку атаки. Префаб содержит меш, Rigidbody, коллайдер и дочерний GameObject, который содержит систему частиц для следа.
- Ракета врезается и создаёт экземпляр префаба взрыва. Префаб взрыва содержит систему частиц, источник освещения, который угасает со временем, и скрипт, который применяет урон окружающим объектам.
В то время как можно собрать объект ракеты полностью из кода, вручную добавляя компоненты и устанавливая свойства, было бы гораздо проще просто создать экземпляр префаба. Вы можете создать экземпляр ракеты просто одной строкой кода, не важно, насколько сложным будет префаб ракеты. После создания экземпляра префаба, вы также можете изменить любые свойства созданного экземпляра объекта (например, вы можете установить скорость Rigidbody ракеты).
Кроме того, что префабы проще в использовании, вы можете позже обновить префаб . То есть если вы собираете ракету, вам нет надобности сразу же добавлять к ней след из частиц. Вы можете сделать это позже. Как только вы добавите след в виде дочернего объекта к префабу, все созданные экземпляры ракет получат след из частиц. И последнее, вы можете быстро настраивать свойства префаба ракеты в инспекторе, упрощая настройку желаемого результата для вашей игры.
Этот скрипт покажет, как запустить ракету используя функцию Instantiate().
// Require the rocket to be a rigidbody. // This way we the user can not assign a prefab without rigidbody public Rigidbody rocket; public float speed = 10f; void FireRocket () < Rigidbody rocketClone = (Rigidbody) Instantiate(rocket, transform.position, transform.rotation); rocketClone.velocity = transform.forward * speed; // You can also access other components / scripts of the clone rocketClone.GetComponent().DoSomething(); > // Calls the fire method when holding down ctrl or mouse void Update () < if (Input.GetButtonDown("Fire1")) < FireRocket(); >>
Замена персонажа на Ragdoll или обломки
Допустим у вас есть вражеский персонаж с ригом и он умирает. Вы можете просто проиграть анимацию смерти и отключить все скрипты, которые обычно отвечают за логику врага. Вам, скорее всего, придётся позаботиться об удалении нескольких скриптов, добавлении некоторой дополнительной логики, чтобы убедиться, что никто не будет атаковать уже мёртвого врага, и о других задачах очистки.
Гораздо лучше будет подход, включающий мгновенное удаление всего персонажа, и замена его созданным экземпляром префаба обломков. Это даёт вам больше возможностей. Вы можете использовать другой материал для мёртвого персонажа, присоединить совершенно другие скрипты, создать экземпляр префаба содержащий объект сломанный на много кусков, чтобы симулировать разбившегося врага, или просто создать экземпляр префаба, содержащий определённую версию персонажа.
Любой из этих вариантов может быть достигнут разовым вызовом Instantiate(). Вам надо просто привязать к нему правильный префаб и всё готово!
Важно помнить, что обломки, которые вы Instantiate() (создаёте их экземпляр), могут быть сделаны из совершенно отличных от оригинала объектов. Например, если у вас есть самолёт, вы можете смоделировать 2 версии. Одна из которых — самолёт, состоящий из одного GameObject с Mesh Renderer и скриптами физики самолёта. Если эта модель будет единым объектом, то игра будет работать быстрее, т.к. вы сможете сделать модель с меньшим количеством треугольников, а ввиду того, что в результате будет меньше объектов, то и рендер будет проходить быстрее. Также, пока ваш самолёт радостно летает вокруг, нет надобности разделять его на части.
Это стандартные шаги, если надо собрать префаб сломанного самолёта:
- Смоделируйте ваш самолёт с различными деталями в вашем любимом приложении для моделирования
- Создайте пустую сцену
- Перетащите модель в пустую сцену
- Добавьте Rigidbody всем частям, выделив все части и выбрав Component->Physics->Rigidbody
- Добавьте коллайдеры Box Collider всем частям, выделив их и выбрав Component->Physics->Box Collider
- Для дополнительного спец-эффекта, добавьте системы похожих на дым частиц в виде дочерних объектов для каждой части.
- Теперь у вас есть самолёт с множеством раздельных деталей. Они будут падать на землю по законам физики и будут создавать след из частиц, в силу того, что к ним присоединены системы частиц. Нажмите Play для предварительного просмотра того, как ваша модель будет себя вести и проведите все необходимые поправки.
- Выберите Assets->Create Prefab
- Перетяните на префаб корневой GameObject, содержащий все части самолёта.
Следующий пример покажет, как эти шаги моделируются в коде.
public GameObject wreck; // As an example, we turn the game object into a wreck after 3 seconds automatically IEnumerator Start() < yield return new WaitForSeconds(3); KillSelf(); >// Calls the fire method when holding down ctrl or mouse void KillSelf () < // Instantiate the wreck game object at the same position we are at GameObject wreckClone = (GameObject) Instantiate(wreck, transform.position, transform.rotation); // Sometimes we need to carry over some variables from this object // to the wreck wreckClone.GetComponent().someVariable = GetComponent().someVariable; // Kill ourselves Destroy(gameObject); >
Размещение группы объектов по заданному шаблону
Допустим вы хотите поместить группу объектов по сетке или кругу. Как всегда, это может быть выполнено двумя способами:
- Сборка объекта полностью из кода. Это утомительно! Ввод значений из скрипта и медленный и не интуитивный, и не стоит затраченных усилий.
- Сделать полностью готовый объект, дублировать его и несколько раз разместить его на сцене. Это опять же утомительно, а размещать объекты точно по сетке достаточно сложно.
Так используйте вместо этого Instantiate() с префабом! Мы думаем, что вы уже поняли нашу идею, почему префабы так удобны в этих случаях. Вот необходимый для этих сценариев код:
// Instantiates a prefab in a circle public GameObject prefab; public int numberOfObjects = 20; public float radius = 5f; void Start() < for (int i = 0; i < numberOfObjects; i++) < float angle = i * Mathf.PI * 2 / numberOfObjects; Vector3 pos = new Vector3(Mathf.Cos(angle), 0, Mathf.Sin(angle)) * radius; Instantiate(prefab, pos, Quaternion.identity); >>
// Instantiates a prefab in a grid public GameObject prefab; public float gridX = 5f; public float gridY = 5f; public float spacing = 2f; void Start() < for (int y = 0; y < gridY; y++) < for (int x = 0; x < gridX; x++) < Vector3 pos = new Vector3(x, 0, y) * spacing; Instantiate(prefab, pos, Quaternion.identity); >> >
Как обновить префаб на всех сценах (везде)?
Версия Unity 2021.3.10f1
У меня есть префаб — окно магазина. Оно состоит из множества картинок, кнопок, других префабов.
Я его изменяю — например меняю размер картинки окна — делаю окно больше.
Сохраняю префаб. Но на других сценах размер окна не меняется.
Как обновить префаб на всех сценах (везде)? Что и где в юнити надо кликнуть? Облазил все настройки — не нашел.
Я понимаю, что префабы можно редактировать, на одной сцене сделать окно больше, на другой меньше.
Но мне надо принудительно сделать окно везде одинаковым.
PS
Сейчас приходится удалять и заново добавлять это окно, что ненормально.
- Вопрос задан 06 авг. 2023
- 185 просмотров
Комментировать
Решения вопроса 0
Ответы на вопрос 1
Охотник на пиратов и сборщик монолитов
Для начала убедитесь, что у вас правильно настроен сам канвас и отображение вообще.
Во вкладке ‘Game’ сверху слева есть выпадающий список с размерами экрана. Выберите тот, на который равняетесь. Затем найдите свой канвас, там рядом должен быть компонент ‘Canvas Scaler’. Установите значения свойств:
* UI Scale Mode : Scale With Screen Size
* Reference Resolution : на то же, что вы поставили во вкладке ‘Game’.
Касательно несинхронизированности префабов. Это происходит когда вы меняете префаб не внутри, а прямо на сцене, не заходя в режим префаба (дабл клик на файле нужного префаба или на стрелке вправо во вкладке ‘Hierarchy’).
Если вы сделали то, что вам нужно, не заходя в режим префаба, в ‘Inspector’ префаба вверху прямо под Tag/Layer будет надпись ‘Prefab’ и выпадающий список ‘Overrides’. Нажмите на него и выберите ‘Apply All’. Таким образом вы сохраните ваш префаб. Если другие это изменение не подтянули, то у них в том же меню выберите ‘Revert All’.
Ответ написан 07 авг. 2023
Комментировать
Нравится Комментировать
Ваш ответ на вопрос
Войдите, чтобы написать ответ

- C#
- +1 ещё
Как в юнити проверить существование сцены по названию?
- 1 подписчик
- 4 часа назад
- 28 просмотров
Советы по работе с префабами в Unity
Всем привет! Меня зовут Григорий Дядиченко, и я технический продюсер. Сегодня хотелось бы обсудить работу с префабами, их организацию и несколько советов по тому, как работать с префабами и с вариантами. Насобирав несколько шишек на проектах у меня сформировалось некоторое число типовых проблем и советов при неправильной организации. Если хотите сделать работу с префабами удобнее, добро пожаловать под кат!

Что такое префаб?

В юнити довольно много удобных инструментов работы с данными, один из которых – префаб. По сути в Unity есть два вида конфигов с визуальным интерфейсом для манипулирования ими. Prefab и ScriptableObject. Если Scriptable Object больше про чистое хранение данных, то Prefab по сути конфиг “аналогичный xaml” в UWP, который позволяет реализовывать концепцию MVVM, и является в ней View. Мне в целом нравится архитектура, когда префабы – это View, компоненты – View-Model, а Scriptable Object – модель. Это довольно удобно. Но в любой другой схеме архитектуры по MVP, MVC и т.п. можно префабы считать за View.
Под капотом префаб или скриптабл обжект – это YAML конфиг. Если в Unity включена текстовая сериализация в настройках редактора то его даже можно открыть и почитать.

Структурно он обычно состоит из ссылок на другие префабы, файлы, скрипты и т.п. и наборы сериализуемых параметров. При этом тут стоит сразу сделать отступление на что такое Prefab Variant. Это такой же YAML конфиг, который похож на префаб в своей сути, но он хранит ссылку на оригинальный префаб m_SourcePrefab и его модификации m_Modification + удалённые компоненты m_RemovedComponents.

Понимать структуру префаб как конфига полезно для пакетной обработки, чтобы обрабатывать его как текст регулярными выражениями и подобными инструментами.
При этом варианты хранят только то, что изменилось, что позволяет сериализацию сделать более компактной для различных “модифицированных” версий объектов в отличии от разных префабов. Единственным исключением из этого правила является набор параметров трансформа (что больше похоже на баг Unity, чем на обоснованную фичу).
Базовые элементы
Разберём все рекомендации на простом пользовательском интерфейсе. Предположим что у нас скажем есть: магазин и награда за квест. Подобный пример позволит нам получить случаи использования похожие на правду и некоторые примеры того, какие проблемы могут возникать. Как и театр начинается с вешалки, сборка интерфейса всегда должна начинаться со сборки базовых элементов. Кнопки, задники окон, рамки предметов и т.п. Что считать базовым элементом зависит от конкретного интерфейса.

Кнопка как базовый элемент будет использоваться по всему интерфейсу, поэтому полезно сначала собрать типовые кнопки с нужными размерами шрифтов и т.п. Важно: в работе с префабами никогда не ленитесь писать названия, потом это сэкономит уйму времени при решении разных задач. Из-за того что это необязательно не стоит считать что это неважно.
Я собрал кнопку из кучи кружков, потому что на самом деле про интерфейс можно сказать так: «Дайте мне один кружок и на нём можно собрать очень много вариантов интерфейса». При этом это очень удобный концепт, так как весить такой интерфейс будет примерно ничего. В дальнейшем кроме каких-то иконок все базовые панели мы так же соберём с помощью одного спрайта-кружка. Вот пример вариантов кнопок:

Теперь соберём по аналогичному принципу фон для окна.

В данном случае у них есть некоторый “общий элемент” bg-circle-shadow. Его конечно же можно вынести в отдельную компоненту, чтобы пакетно красить тени, менять их реализацию и т.п. Но по опыту в разных сущностях лучше не обобщать такие элементы, так как именно из-за этого потом возникают проблемы “я поменял кнопку, а сломались все окна”. Изменение префабов с помощью инструментов Unity — слишком простое действие. Но тем не менее не хочется терять возможность пакетной обработки. Поэтому лучше заранее продумать контракты названий и манипулировать пакетно либо скриптами, либо в ручную, но осознанно меняя в определённых местах. Такие вещи на самом деле не так сложно читать на ревью в мерж реквестах, когда названия совпадают или имеют нечто общее. Так что разбор всего уж совсем на молекулы – это, как и в коде, излишняя декомпозиция, которая ведёт в будущем к неочевидным проблемам. Сущности должны быть разделены логически. И совсем базовые компоненты не должны пересекаться. Ну почти, но мы этого коснёмся чуть позже.
Из базовых элементов мы собрали всё, кроме “игрового предмета”.

Он аналогичен. Так сказать из того, что можно собрать на стоках, собрали для иллюстрации. Перед тем как начать собирать окна, немного ещё по базовым элементам. Базовые элементы интерфейса – это не эффекты или какие-то поведения на мой взгляд, чтобы с ними было удобно работать, а конкретные базовые сущности. Фоны, кнопки, прогресс бары для интерфейса. Персонажи, мечи, игровые объекты – которые могут повторяться и удобно редактировать пакетом. Основной плюс сборки сразу такого UI кита заключается в том, что дальше окна уже собираются довольно быстро, так как по сути это копирование и изменение значений, но основные ингредиенты окна уже собраны. Итак, начнём собирать окна.
Композиция или Nested Prefabs
Перед сборкой стоит рассказать про композицию и Nested Prefabs. В самой сборке нет ничего особо интересного, она скорее представлена для иллюстрации концепта. Префабы как сущность в движке обладают одной проблемой. Из-за того, как просто ими манипулировать, собирать и управлять, то многие очень халатно подходят к сборке и не учитывают насколько это важный элемент, который при правильном структурировании и аккуратной работе с ним может сэкономить в будущем уйму времени. По сути в Unity сейчас есть два механизма для работы с префабами композиция (Nested Prefabs) и наследование (Prefab Variance) и относится к ним нужно так же, как и к тем же механизмам в коде. Только с ещё с большей осторожностью, так как в префабах в принципе нет “защиты от дурака” Префаб просто позволяет определять View и делать биндинги без кода, но это всё ещё View. И всё ещё те же механизмы встречающиеся в разработке и их проблемы.
С композицией всё довольно просто. Она не всегда удобна, излишняя композиция ведёт к проблемам которые я описывал для базовых элементов и теней. То есть любой объект должен быть разбит на логические сущности. Если что-то присуще только этому окну – нет смысла выносить это в отдельный префаб. Самый простой способ определить это задать себе вопрос. Если я изменю этот элемент мне придётся менять это окно? Как можно заметить в базовых элементах у нас скажем не было заголовков окон. Если у окон нет некоей обобщённой вёрстки, то чаще всего мы не может рассуждать так:
“Итак, у нас есть заголовки. Хорошим тоном при работе шрифтов, что по всему приложению у нас есть несколько размеров шрифта и для заголовочных он свой. Поэтому вынесем это в префаб, чтобы менять размер шрифта по всему приложению для заголовков”
Идея, имеет место быть. Но в среднем по опыту такой подход ведёт к тому, что разработка узнаёт от тестеров о том, что “а вот тут сломался такой то экран, текст теперь залезает туда”. И это и есть излишняя декомпозиция. Всё зависит от конкретного случая, иногда окна скажем можно разбить на повторяющиеся виджеты, которые просто складываются друг на друга через horizontal layout, если дизайн такие молодцы и так сделали. Но это скорее исключение чем правило.
Соберём из наших компонент префаб окна награды за квест (я бы конечно ещё поиграл со шрифтами и хедером, но это только для статьи так что попрёт)

Получается такая композиция базовых элементов. Удобно, что если скажем у нас дизайн решит что кнопки подтверждения теперь должны быть оранжевыми их можно поменять везде через префаб, а если только в окне квестов, то зайти в префаб окна квеста и поменять там. При этом хочется обратить внимание на несколько моментов, которые я так же считаю весьма удобными.
Первое – это добавление в конец названий префаба предполагаемого действия. Это полезно в поиске, в авто-редактировании, в групповом редактировании объектов по принципу их действия и т.п. Тут можно завести удобный для себя контракт.
Второе – я специально на скриншотах захватываю весь экран, так как организация папок это важно. Не именно такая, каждому можно быть удобно своё в зависимости от контекста проекта. Но когда хорошая вложенность папок и всё логически разделено + панели отдельно от базовых элементов – это сильно упрощает навигацию в дальнейшем. Так же, как и смена стиля написания названий панелей (слонов) и базовых элементов (мелкими через дефис)
Третье – тут это не так хорошо видно, но организация папок с текстурами. Unity sprite atlas позволяет передавать папку в качестве параметра с текстурами. Поэтому если какие-то текстуры принадлежат какому-то игровому экрану, то лучше класть их в отдельную подпапку. Перед релизом игры может встать задача оптимизации интерфейсов. И тогда это так же сэкономит кучу времени, так как допустим одна из оптимизаций – это сгруппировать текстурные атласы по игровым экранам, чтобы уменьшить число draw call на интерфейс. Так как для того, чтобы интерфейс рисовался в скажем 1 dc одно из требований, чтобы все спрайты этого интерфейса лежали в одном атласе. Я в примере буду во всех экранах использовать одни и те же текстуры, так что у меня этого разделения нет.
Наследование или Prefab Variants

По своей сути же Prefab Variants – это наследование в префабах, которое позволяет расширять функционал наследников со всеми из этого вытекающими. Как базовая рекомендация в таком случае – не делать очень глубокую иерархию наследования. Если относится к префабам, как к коду, где всё довольно просто, чётко и иерархически, то все советы выполняются сами собой. Просто многие обращают на это недостаточно внимания и тратят уйму времени на поддержку подобных решений.
Соберём теперь окно для магазина:

И вот у нас уже появились префаб варианты. Они пока не обязательные на самом деле, скорее для иллюстрации концепции. Если бы в награде квеста у нас скажем была статичная иконка, а в магазине она периодически мигала или по ней проходил бы блик, чтобы привлекать внимание.
Важно: для окна квеста мы создали новый вариант game-item-quest-reward и он унаследован от game-item, так же как и game-item-shop унаследован от game-item. Очень частая ошибка, что если делается первым скажем окно QuestPanel, то там остаётся базовый game-item, или получается цепочка наследования game-item->game-item-quest-reward->game-item-shop, что в свою очередь очень плохо с точки зрения проектировки. Так как игровой предмет магазина по логике не должен зависеть от предмета в окне награды за квест. Они могут опираться оба на один базовый, но ни в коем случае нельзя строить такую зависимость. Хотя интерфейс Unity к этому подталкивает.
И вот у нас появились префаб варианты. Вариант красной кнопки – это удобно, но не обязательно. Просто верстая много окон или собирая их под разные аспекты в адаптивной вёрстке, очень часто нужно использовать кнопки разных цветов. И поэтому чем каждый раз красить зелёную удобнее просто сделать вариант. По сути это отдельный логический объект (именно визуальный), так как это кнопка отмены. Для кнопки которая во всём интерфейсе встречается один раз я бы не стал делать отдельный вариант, а это достаточно типовое разделение.
Ещё стоит обратить внимание, что структурно фон карточки сейчас – это тот же фон окна. Но тогда почему это отдельный префаб? Потому что это отдельная логическая сущность никак не связанная с фоном окна, и не должна изменяться вместе с изменением фона окна. А почему это не вариант, как сделано с игровым предметом? Так можно сделать, тут уже вопрос к тому насколько вы считаете эти сущности разными. Я считаю это рискованным при горизонтальном масштабировании, так как когда таких сущностей не 2-3, а 20-30 трудно следить за их изменениями. А при этом для пакетной обработки можно пройтись по ним скриптом, либо руками.
В заключении
Надеюсь данные советы и рекомендации сделают ваш проект лучше и будут полезны. Я лишь обращаю внимание на то, что не стоит к префабам относится халатно, так как изначально хорошо организованная структура экономит уйму времени при разработке проекта в дальнейшем.
В разработке, и префабы не исключение, есть базовый конфликт. С одной стороны хочется, чтобы правки меняли только тот модуль, который исправляется. Это упрощает разработку и не вызывает неочевидных багов, когда правка касается только конкретного модуля. А с другой стороны хочется удобства, чтобы из-за “дублирования” не приходилось одно и тоже при ошибке менять в каждом месте всей системе. И любая разработка – это компромисс между этими двумя стульями.
В общем резюмируя:
- Следите за названиями объектов
- Не делайте слишком глубокую иерархию вариантов и разделяйте их логически
- Для базовых элементов, виджетов собираемых в окно лучше использовать Nested Prefabs и композицию
- Не обманывайтесь интерфейсом и простотой редактирования. За префабами надо следить не меньше чем за кодом
Собранные префабы вы найдёте в этом репозитории, где можно посмотреть на организацию. Спасибо за внимание!