Как сделать копию объекта в unity

Обновлено: 07.07.2024

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

Там проблема: почти все в Unity проходит по ссылке. Есть ли способ сделать то, что я хочу сделать, или нет такого пути?

Если вы хотите создать сцену, объединив несколько экземпляров GameObjects, созданных во время выполнения, вы можете создать скрипт с именем generateEnviroment.cs (просто имя примера), затем вы должны передать один или несколько GameObjects в качестве атрибутов этого скрипта от инспектора.

Следующим шагом является создание правильного объекта gameObject, а затем изменение его свойств по вашему усмотрению (позиция, размер, материал. ). Каждый экземпляр будет независимым, с его собственными атрибутами, которые вы можете изменить по своему желанию, а другие экземпляры одного и того же GameObject не будут изменены.

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

В этой статье попробуем разобрать что такое Scriptable object, зачем они нужны и как их использовать.

Файлы и данные

Работать с файлами в редакторе unity достаточно просто. Каждый файл отображает только свои параметры, если это изображение, то мы видим настройки разрешения, детализации и тд, если это текст, то мы можем увидеть, что написано в нем, а если это 3D модель, то можем увидеть ее в окошке Preview и даже покрутить. Все это конечно удобно, но что если нам понадобится особый объект который мог бы сочетать в себе несколько типов данных одновременно, к примеру сделать так, чтобы в одном файле хранилась и картинка и, допустим, текст с ее описанием? Для решения этой проблемы и был введен особый тип объектов в unity – Scriptable object.

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

Попробуем на примере разобрать, как выглядят скриптовые объекты и чем они отличаются от любых других объектов unity. Создадим простой скрипт ImageData, который будет обычным классом и хранить в себе изображение Sprite, и текст с его описанием.

  1. publicsealedclass ImageData
  2. public Sprite image ;
  3. publicstring description = “Description here” ;
  4. >

Если создать экземпляр данного класса с помощью оператора new :

ImageData data = new ImageData ();

то этот экземпляр будет существовать только в оперативной памяти компьютера до тех пор, пока программа не завершит свою работу, после чего память очистится и объект ImageData будет уничтожен. Чтобы можно было постоянно хранить этот объект в проекте после создания, необходимо унаследовать ImageData от класса ScriptableObject и создать уже не просто “виртуальный” экземпляр объекта, а его постоянную форму в виде файла.

  1. publicsealedclass ImageData : ScriptableObject
  2. public Sprite image ;
  3. publicstring description = “Description here” ;
  4. >

Создавать экземпляры скриптовых объектов можно вызвав статический метод CreateInstance класса ScriptableObject. Выполнять это действие необходимо только в редакторе, для чего воспользуемся методами “быстрого” доступа – это статические методы, которые вызываются с помощью контекстного меню внутри редактора.

Атрибут MenuItem добавит статический метод CreateImageData в специальное контекстное меню которое будет доступно в разделе Assets -> Create -> New image data instance.


В самом методе создадим экземпляр скриптового объекта ImageData.

При вызове статического метода CreateInstance, в скобки передается тип создаваемого объекта, в нашем случае это тип ImageData. После того как экземпляр создан, необходимо его сохранить в проекте, для чего воспользуемся специальным классом по работе с ассетами в редакторе – AssetDatabase и его статичеким методом CreateAsset для сохранения объектов в виде файла.

В метод CreateAsset передаем объект ImageData, который необходимо создать и указываем путь, где он будет создан, в данном случае объект будет создан в корневой папке Assets. Чтобы протестировать процесс создания скриптового объекта, можно перейти в контекстное меню Assets -> Create -> New image data instance и нажать его.


Теперь в папке Assets у нас появился новый файл скриптового объекта в который мы можем поместить изображение и текст с описанием.


Итак, экземпляр скриптового объекта ImageData перешел из “виртуального” вида и хранится теперь в постоянной памяти вместо оперативной. Этот файл мы можем редактировать, удалять, перемещать и тд, в каком то смысле теперь объект стал “осязаем”, что намного облегчает работу с ним. Самое главное преимущество скриптовых объектов перед другими видами файлов в том, что эти объекты могут хранить самые необходимые данные, точнее – только те, которые вы укажете.

Для сравнения возьмем обычный префаб. Префаб – это сложный GameObject который может содержать в себе другие GameObject’ы, а также кучу компонентов, которые вам могут показаться совершенно бесполезными.


В скриптовом объекте вы указываете только те данные, которые вас интересуют, без лишних компонентов и других данных, при этом сохраняются все возможности работы со скриптовым объектом как и с любым другим unity объектом.


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

К примеру: на сцене есть 1000 GameObject’ов, у каждого объекта есть компонент, в котором необходимо указать ссылку на изображение, ее размеры Vector2 и текст с ее описанием, в этом случае все 1000 объектов будут создавать свои уникальные ссылки на эти данные, что в общем кол-ве будет давать 3000 (1000 объектов умножить на 3 вида данных) уникальных ссылок, что совершенно не нужно, так как достаточно просто создать один скриптовый объект со всеми этими данными и передавать в компонент одну ссылку на скриптовый объект вместо 3х.

И в третьих – заменяемость. Для создания копий экземпляра скриптового объекта, достаточно использовать Instantiate, как и при создании копии любого префаба, после чего получаем абсолютно новую и независимую копию объекта.

Использовать скриптовый объекты так же легко как и любые другие объекты в unity.

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


В самом компоненте, для получения ссылок на скриптовые объекты необходимо просто указать тип ImageData.

  1. publicsealedclass ImageControl : MonoBehaviour
  2. public ImageData [] data = new ImageData [ 5 ];
  3. >

Мы уже разобрали способ создания скриптовых объектов через статический метод. Есть еще один способ создания экземпляров скриптовых объектов – через специальный атрибут CreateAssetMenu .

  1. [ CreateAssetMenu ( fileName = “New image data” , menuName = “New image data” , order = 0 )]
  2. publicsealedclass ImageData : ScriptableObject
  3. public Sprite image ;
  4. publicstring description = “Description here” ;
  5. >

Результат будет такой же, как если бы создавали через статический метод контекстного меню. Достаточно просто поместить данный атрибут вверху класса ImageData, после чего указать название файла при создании и места, где будет располагаться его контекстное меню. В данном случае там же в Assets -> Create -> New image data. Единственный недостаток такого решения в том, что нельзя будет указать место создания файла, по умолчанию это будет корневая папка Assets.

Скриптовые объекты и ООП

В начале статьи мы разбирали простой класс ImageData, который еще не был унаследован от ScriptableObject, и создавали экземпляры данного класса с помощью оператора new. Экземпляры скриптовых объектов также можно создавать с помощью этого оператора.

К примеру, усовершенствуем немного класс ImageData и добавим ему конструктор, в котором будет указывать изображение и текст с описанием.

Теперь можно создать экземпляр класса ImageData использую его конструктор.

  1. Sprite image ;
  2. string description ;
  3. ImageData data = new ImageData ( image, description );

Данная конструкция создает “виртуальный” экземпляр скриптового объекта, это именно то, с чем мы боролись использую скриптовые объект – перейти от “виртуального” типа к “физическому”. Хотя такая конструкция создания очень удобная при создании сложных экземпляров, сохранять такие экземпляры нельзя. Для решения данной проблемы необходимо поместить “виртуальный” экземпляр в “физический” шаблон, созданный через статический метод CreateInstance.

В методе CreateImageData создается новый экземпляр скриптового объекта ImageData, только в этот раз с помощью оператора new. После чего экземпляр передаем в метод SaveInstance для сохранения его в виде постоянного файла. Так как сохранять “виртуальные” экземпляры не получится, необходимо создать его “физический” шаблон скриптового объекта такого же типа как и оригинал, после чего просто передать на него ссылку и сохранить.

В переменную saveObject помещаем новый “физический” шаблон такого же типа как и оригинал, для этого в новом статическом метод CreateInstance указываем тип передаваемого объекта, вызвав его метод GetType.

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

Скриптовые объекты могут вам очень пригодится когда необходимо создать постоянную базу данных в виде файла, которую удобно редактировать, перемещать и передавать другим объектам. Эти объекты одновременно совмещают два способа работы: программный – на уровне кода, и файловый.

С сохранением всего функционала. По рекомендациям зарубежного интернета пробовал дублировать папки Assets и Project settings - физика игры испорчена, Камера не двигается, и т.д. Проьовал делать Export Package- то же самое: все ассеты импортируются но все остальное кривое, не работает и сломано.

Просто скопировать всю папку с проектом!

DanielDem
Папки Library и Temp - не обязательны.
Данные в них сгенерируются заново.


DenPixel
Видимо ты что-то не так делаешь.
При копировании Assets и ProjectSettings все должно быть норм.

DenPixel
У тебя там нет хитрых скриптов завязанных на путь к папке?

всегда работало скопировать папку Assets, ничего не ломалось при этом, хотя пару раз помню некоторые теги не перенеслись, но ничего критичного

file— saveproject—- name1
file—saveproject—-name2

Нужны папки: Assets, ProjectSettings, Packages (с недавних пор, раньше её не было). Ещё нужно проследить, чтобы не потерялись .meta-файлы внутри Assets, иначе потеряются настройки импорта всех ассетов и все ссылки между ассетами. Мета-файлы могут быть скрытыми (в зависимости от настроек проекта).

Кроме того, как я могу выбрать объект для клонирования во время выполнения? (выбор мыши предпочтительнее).

3 ответа

Как я могу создать gameObject в gameObject? Привет всем, я не могу решить эту проблему решения, не знаю почему, но это не работает, я новичок в unity 3d, так что, возможно, я сделал ошибки при написании кода и спасибо всем, кто уделяет мне свое время. мне нужно от вас предложение, как я могу это.

Есть кое-что, чего я пытаюсь достичь, - это уничтожить экземпляр объекта (который является системой частиц). Проведя некоторые исследования, я обнаружил, что способ создания и уничтожения экземпляра объекта заключается в следующем: public class CoinCollider : MonoBehaviour < public Transform.

И вы захотите, чтобы это происходило в течение многих звонков для обновления:

Если ваш скрипт прикреплен к GameObject (скажем, к сфере), вы можете сделать это:

Вы даете Instantiate( ) три параметра: какой объект, в каком положении, как он вращается.

Что делает этот скрипт, так это создает экземпляр чего-то в точном положении & вращения GameObject, к которому прикреплен этот скрипт. Часто вам нужно будет удалить коллайдер из GameObject и жесткое тело, если оно есть. Существуют различные способы создания экземпляров вещей, поэтому, если это не сработает для вас, я могу привести другой пример. : )

(Первая строка просто гарантирует, что к объекту прикреплен коллайдер, он необходим для обнаружения щелчка мыши)

Этот сценарий должен работать как есть, но я еще не тестировал его, я исправлю его, если это не так.

Похожие вопросы:

У меня есть UIScrollView на нем у меня есть UIImageView 's и UIButton , когда я создаю temp UIScrollView и пытаюсь сделать что-то вроде этого: for (UIView *viewCopy in scrollView.subviews)

Как создать независимую копию объекта route ? Проблема в том, что все обновления, примененные к route_copy , также применяются к route . Как этого избежать? public class Route implements Cloneable.

Мне нужно временно сохранить содержимое NSManagedObject в словаре. Поскольку core data имеет свои собственные процедуры управления памятью, я не хочу держать какие-либо сильные указатели на поля.

Как я могу создать gameObject в gameObject? Привет всем, я не могу решить эту проблему решения, не знаю почему, но это не работает, я новичок в unity 3d, так что, возможно, я сделал ошибки при.

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

Положение плоского объекта в положение плоскости GameObject. В основном я создал плоскость, основанную на трех точках. Но для проверки мне нужно знать, где находится самолет. Итак, у меня есть.

Я создаю небольшую многопользовательскую онлайн-игру. и мне удалось сделать несколько шагов. Я настроил префаб плеера и благодаря этому мне удалось создать экземпляр объекта в сцене: [Command] void.

Я беру онлайн-класс по разработке игр с использованием unity, инструктор иногда может быть расплывчатым. У меня сложилось впечатление, что использование gameobject-это то же самое, что использование.

Я хочу из сценария создать экземпляр gameobject, но gameobject, который я хочу создать, должен быть родителем другого Gameobject. Как это сделать?

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

Читайте также: