Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 14 Next capture
2021 2022 2023
2 captures
13 Jun 22 - 14 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
3
Question by Orion 1 · Oct 27, 2010 at 10:56 AM · editorcloneresetduplicate

How to reset a component on duplication?

I have a component, that I want to automatically reset when the game object it is attached to is duplicated / cloned in the editor.

I have tried doing this with a stored ID, and every time you inspect the component it looks through the whole scene for other objects with the same ID and if there is one, resets itself. But this is a very clumsy way of doing it, and it's very specific (I have to individually reset every variable).

Is there a way to reset a component?

Is there a way to catch duplication?

Is it possible to do this from a custom editor instead of the component itself (lets say I don't have access to the component's script)?

Comment
Add comment · Show 2
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Statement · Dec 06, 2010 at 02:51 PM 0
Share

Is it supposed to be an editor duplication event, or a run-time duplication event? Have you tried calling Reset() during OnEnable() ?

avatar image Orion 1 · Dec 09, 2010 at 10:03 AM 0
Share

It indeed is supposed to be editor duplication, which does not call OnEnable().

4 Replies

· Add your reply
  • Sort: 
avatar image
1

Answer by CaseyHofland · Aug 11, 2020 at 09:58 PM

Late but for new readers: Here is the definitive way to do it!

 public class Foo : MonoBehaviour
 #if UNITY_EDITOR
     , ISerializationCallbackReceiver
 #endif
 {
     private GameObject childObject;
 
 #if UNITY_EDITOR
     [HideInInspector] [SerializeField] private GameObject _childObject;
     private bool isDuplicate = true;
 
     public void OnBeforeSerialize() 
     {
         // Security check in case of Reset.
         if(childObject)
         {
             // Serialize the childObject for the next time we duplicate.
             _childObject = childObject;
         } 
     }
 
     public void OnAfterDeserialize()
     {
         if(isDuplicate)
         {
             // Delay these calls since gameObjects can't be accessed during Deserialization.
             UnityEditor.EditorApplication.delayCall += OnDuplicate;
             UnityEditor.EditorApplication.delayCall += Reset;
         }

         // Security check in case of domain reload.
         if(_childObject)
         {
             // Reassign the serialized childObject.
             chilldObject = _childObject;
         }
     }
 
     private int siblingIndex = -1;
     private void OnDuplicate()
     {
         // Destroy the duplicated child.
         siblingIndex = childObject.transform.GetSiblingIndex();
         DestroyImmediate(transform.GetChild(siblingIndex).gameObject);
     }
 
     private void Reset()
     {
         // Create a new child and set it to our siblingIndex (in case of duplication).
         isDuplicate = false;
         childObject = new GameObject();
         childObject.transform.SetParent(transform);
         if(siblingIndex > -1)
         {
             childObject.transform.SetSiblingIndex(siblingIndex);
         }
     }
 #endif
 }


This way we can do whatever junk we need to do in OnDuplicate (if we need it) and still call Reset afterwards. Since this is all done with Serialization, we can keep our Awake method clean and wrap this all in an #if UNITY_EDITOR, no [ExecuteAlways] required!

If you do experience trouble with this please let me know.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Stacklucker · Oct 28, 2021 at 06:55 AM 0
Share

But won't this trigger OnDuplicate after every recompile/reloading since isDuplicate is not getting serialized?

avatar image
0

Answer by Max Kaufmann · Oct 28, 2010 at 02:17 AM

You could save the "restored" version as a prefab, and instance off of that?

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Orion 1 · Nov 02, 2010 at 09:39 AM 1
Share

Hm. Using a prefab would be tricky, as I then need very specific code to get instantiate the prefab, get the right component out of it, read its data and remove the instance again. Plus I have to create prefabs for pretty much everything.

But the most important issue for me is to catch when the duplication actually happens.

avatar image
0

Answer by IzzySoft · Dec 29, 2014 at 11:24 PM

Hmm... Have you tried:

 [ExecuteInEditMode]
 public class myObject : MonoBehaviour
 {
     [NonSerialized] public bool isDuplicate = true;
 
     void Awake()
     {
         myObject mo = this as myObject;
         
         Debug.Log( "In Awake. isDuplicate: " + myObject.isDuplicate );
         
         if( myObject.isDuplicate )
             Reset();
     }
 
     void Reset()
     {
         myObject mo = this as myObject;
         
         // re-set/intialize NonSerialized members, shared meshes, etc...
         
         myObject.isDuplicate = false;
     }
 
 }

One drawback is, Reset() will get called 2 times when you Duplicate your object in the Unity editor. Sorry. :/

Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image
0

Answer by bjennings76 · Jun 17, 2015 at 06:26 AM

I wasn't able to find a good way to directly call the 'Reset' function that the Inspector menu has, but I was able to cheat by deleting/recreating the component when it's instance ID doesn't match the saved one:

 [ExecuteInEditMode]
 public class ResetTest : MonoBehaviour
 {
     public int TestNumber;
     [HideInInspector] public int MyID;
 
     private void OnEnable()
     {
         if (MyID == GetInstanceID()) return;
         if (MyID == 0) MyID = GetInstanceID();
         else
         {
             gameObject.AddComponent(GetType());
             DestroyImmediate(this);
         }
     }
 }

Down side is this will 'move' the component to the end of the component list on the duplicated object. If your component order is important, that would be a problem.

If you don't want to use the ever-finicky [ExecuteInEditMode], you can do the same trick from a custom editor:

 [CustomEditor(typeof (ResetTest))]
 public class ResetTestEditor : Editor
 {
     private void OnEnable()
     {
         var t = (ResetTest) target;
         if (t.MyID == t.GetInstanceID()) return;
 
         if (t.MyID == 0) t.MyID = t.GetInstanceID();
         else
         {
             t.gameObject.AddComponent(t.GetType());
             DestroyImmediate(t);
         }
     }
 }

Which also cleans up the the class:

 public class ResetTest : MonoBehaviour
 {
     public int TestNumber;
     [HideInInspector] public int MyID;
 }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image soulburner · Jul 14, 2020 at 11:04 AM 0
Share

That doens't work because GetInstanceID() would return a different value each for the same objects time you load the scene.

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

6 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

How do I properly duplicate an object in a editor script? 3 Answers

Cloning GameObjects with custom inspector script attached 0 Answers

How to have a cloned/duplicated enemy react the same way the original does? 1 Answer

Editor Wizard: Copy Existing Components to Another GameObject 2 Answers

how to clone several game objects in a way that clone properties of one can be adjusted to match all others in scene view 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges