Создание экземпляров префабов во время работы приложения
К данному моменту вы уже должны понимать основы концепта префабов (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. Инициализация объекта.
Постигаю премудрости опытным путём с помощью шишек и зарубок от грабель)
В процессе родился вопрос.
У меня такая ситуация:
Есть префаб, на нём висит MonoBehavior, который определяет некоторое поведение.
В MonoBehavior я реализовал Start, который обращается к некоторому полю A.
В префабе это поле равно null. Значение его будет известно только на момент «создания» объекта на сцене(в каком-то другом классе(тоже MonoBehavior))
Т.е. в какой-то момент я делаю что-то вроде:
Instantiate (prefab, somePosition, someRotation);
Далее происходит следующее: В MonoBehavior, который висит на prefab, я получаю NullReferenceException, т.к. отрабатывает метод Start и на момент его работы свойство A равно null.
Вопрос, что с этим делать?
Разумеется, очевидное лобовое решение, которое пришло мне в голову: где-то сразу после появления объекта на сцене инициализировать свойство A(ну мало ли, вдруг успею до вызова Start:)). Это вылилось вот в такой говнокод:
var instance = Instantiate (prefab, somePosition, someRotation); instance.A = someValue;
Я в принципе сразу понимал, что это не поможет, но решил попробовать и ожидаемо выхватил всё тот же NRE на том же месте.
Как это ПРАВИЛЬНО победить?) Есть какой-то паттерн на эту тему? По идее мне нужно, чтобы мой объект имел нужные значения поля(полей) на момент, когда он появится на сцене(т.е. до вызова Start\Awake).
#1
17:37, 27 фев 2018
snowslip
> В префабе это поле равно null.
> Значение его будет известно только на момент «создания» объекта на сцене(в каком-то другом классе(тоже MonoBehavior))
Не совсем понимаю что тебе нужно. Может Script Execution Order Settings поможет?
#2
17:48, 27 фев 2018
давай подробней расскажу:
Я хочу создать на карте моба и сказать, куда ему ползти. При этом для разных мобом места назначения разные.
Для этого у меня есть MobSpawner(это наследник MonoBehavior). В нём(в момент, когда нужно создать мобов) происходит вызов:
Instantiate (mobPrefab, somePosition, someRotation);
На mobPrefabв свою очередь висит скрипт Mob(тоже наследник MonoBehavior). В скрипте реализован метод Start, который использует(в нуждах реализации некоторой «бизнес-логики») знание о конечной точке прибытия моба.
Соответственно я должен как-то передать знание о точке прибытия моба после того, как сработает Instantiate(т.е. после поялвения моба на сцене), но до того, как отработает метод Start в скрипте Mob.
- patsanchik3
- Постоялец
#3
17:59, 27 фев 2018
GameObject instance = Instantiate (prefab, somePosition, someRotation);
instance.GetComponent().A = someValue;
#4
18:12, 27 фев 2018
Но Start же имеет шанс успеть быть вызванным до осуществления присваивания.
Как я написал в самом посте, так я попробовал сразу. Start успевает раньше добраться до этого поля.
- patsanchik3
- Постоялец
#5
18:18, 27 фев 2018
snowslip
> Как я написал в самом посте, так я попробовал сразу. Start успевает раньше
> добраться до этого поля.

#6
18:19, 27 фев 2018
snowslip
Что мешает создать в скрипте Mob функцию go(), передать туда параметры, а функцию Start() не использовать для этого. Создал объект и вызвал go() сказал куда идти.
#7
18:36, 27 фев 2018
using UnityEngine; public class Cube : MonoBehaviour < public Transform tr; public float x; void Start( ) < x=tr.position.x; >void Update( ) < >>
using UnityEngine; public class Spawn : MonoBehaviour < public void onButtonSpawn( ) < Vector3 pos=new Vector3( Random.Range( -5.0f,5.0f),0.0f,Random.Range( -5.0f,5.0f)); var obj=Instantiate( Resources.LoadGameObject>( "Cube"),pos,Quaternion.identity); var cube=obj.GetComponentCube>( ); cube.tr=GetComponentTransform>( ); > >
#8
18:38, 27 фев 2018
patsanchik3
А можешь резюмировать?) Какой вывод из изображения следует?
Я не вижу там противоречия своим словам: где-то после Awake и OnEnable мне нужно успеть сделать присваивание, но я не успеваю.
s3dworld
О, вот это похоже на решение.
#9
18:41, 27 фев 2018
s3dworld
Не, в твоём примере проблем может и нет. Но это что вроде ошибки выжившего) В твоём случае скрипт успел. Но гарантий,что так будет всегда, нет
#6 – Создание объектов (Instantiate)

При помощи метода Instantiate вы можете в Unity создавать различные объекты через скрипт. В ходе урока вы научитесь использовать этот метод на практике. К тому же, вы разработаете небольшой проект с созданием случайных объектов в случайных местах.
Видеоурок
Важной частью Unity является возможность создания новых объектов прямиком из скриптов. Для этого используется специальный метод Instantiate. Он принимает три основных параметра:
- Prefab – объект, что будет создан;
- Vector3 – место, где будет создан объект;
- Quaternion – стартовое вращение объекта.
Instantiate и Canvas s Unity?
Для начала вам нужно получить трансформ Canvas. Сделать это можно двумя способами (на самом деле больше, но тут основные): 1) Повесить тег на Canvas, и потом использовать FindGameObjectWithTag. 2) Сделать в классе, где будет вызываться Instantiate поле Transform для Canvas, и либо при старте сделать первым способом, либо вручную перетащить Canvas в Unity в это поле.
Потом после Instantiate у созданного объекта (назовем его go) делаем go.transform.SetParent(*трансформ нашего canvas*)
Ответ написан более трёх лет назад
Комментировать
Нравится 1 Комментировать
firehead16 @firehead16
Изображение, которое должно появиться добавьте в public GameObject name , со стврта пишите name.SetActive(false) и присваиваете true после instantiate
Ответ написан более трёх лет назад
Комментировать
Нравится 1 Комментировать
Ответы на вопрос 0
Ваш ответ на вопрос
Войдите, чтобы написать ответ

- C#
Как преобразовать List в строку?
- 1 подписчик
- 3 часа назад
- 61 просмотр

- C#
- +1 ещё
Как проверять столкновение префаба и UI панели в Unity?
- 1 подписчик
- вчера
- 39 просмотров