Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Does Transform.SetParent() actually duplicate the object for a moment?

Discussion in 'Scripting' started by Tom163, Sep 14, 2022.

  1. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,274
    I'm having trouble where code that is supposed to pick up a small number (4-8) of child objects with a specific tag actually creates phantom duplicates. The reason I notice this is that I collect them in a list and at the end of the code that list has twice as many entries as it should and the first half of the list is all "None".

    Tracing my code I come to a point where a "transform.SetParent()" call causes an Awake() on the kid objects to trigger. The only explanation I have and I'd like to check if this is true, is that SetParent() actually clones the object, and immediately deletes the original, and somehow my code picks it all up in the exact moment (frame?) that both objects exist.

    Is this possible or am I chasing ghosts?
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    No, cloning a hierarchy just to set a parent would be an exercise in madness. That would make iy really costly in lots of cases. It's only assigning a reference to the parent. Behind the scenes there's the TransformDispatch which is a mechanism to allow systems to poll for changes such as Transform change and there is a mechanism to get a callback on parent change.

    Maybe you're seeing something that a particular system is doing but I've never seen the MonoBehaviour "Awake" called because of a parent change which, in my opinion, would be a serious bug if so.
     
  3. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,274
    I have attached a trivial Monobehaviour to the object that calls Debug.Log() in Awake() and the stack trace in that tells me that the SetParent() call is the one right before the Awake(). I was surprised as well, but I find no other explanation.
     
    MelvMay likes this.
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    Yeah, maybe that is some odd behaviour I'm not aware of but that does surprise me. You're sure the Awake isn't before the SetParent? Not that this is my area of expertise but would you mind posting the stack as I'm super curious now! :)

    I'm looking through the C++ source because it's my start of day and I have a strong cup of coffee and curiosity has got me.
     
    orionsyndrome, mopthrow and Bunny83 like this.
  5. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,572
    SetParent can trigger the Awake of an object if:
    1. The child is originally attached to a parent that was deactivated, but the child itself is activated. As a result the child would not get its Awake method called, because it's deactivated in hierarchy
    2. When you use SetParent on that object and move the child to a parent that is active (or unparent by passing null), the child would become active at that moment and Awake should be called.
    Without seeing some relevant code we can't really tell what's going on.
     
  6. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,274
    Here's what I got from the trace:

    Workspot Awake
    UnityEngine.Debug:Log (object)
    Workspot:Awake () (at Assets/0_game/Prefabs/Buildings/Workspot.cs:8)
    UnityEngine.Transform:SetParent (UnityEngine.Transform)
    BlackForest.BuildingVisualsNew:Setup () (at Assets/0_game/Prefabs/Buildings/ProceduralHouses/BuildingVisualsNew.cs:117)
    UnityEngine.Events.UnityEvent:Invoke ()
    FIMSpace.Generating.PGGGeneratorBase:GenerateObjects () (at Assets/FImpossible Creations/Plugins - Level Design/PGG/Core/Helper Components/Bases/PGGGeneratorBase.cs:51)
    FIMSpace.Generating.SimpleFieldGenerator_GenImplemented:GenerateObjects () (at Assets/FImpossible Creations/Plugins - Level Design/PGG/Components/Simple/SimpleFieldGenerator_GenImplemented.cs:39)

    Here's what the code around BuildingVisualsNew.cs line 117:


    Code (CSharp):
    1.             foreach (Transform t in allTransforms) {
    2.                 if (t != null && t.tag == "Workspot") {
    3.                     Debug.Log("workspot found: "+t.name+" - will be renamed to #"+count.ToString());
    4.                     t.SetParent(ws.transform);
    5.                     t.gameObject.SetActive(true);
    6.                     t.name = "Workspot "+count.ToString();
    7.                     count++;
    8.                 }
    9.             }

    It might be what you describe. I do deactivate the parent GO in code, that's why I fetch out the child objects (because I need them). So this might be unrelated to the objects becoming duplicated, interesting.

    I'll do more debugging, at least I now know that my problem isn't some one-frame copy issue within the engine.
     
    Bunny83 likes this.
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,623
    Yes, my response was (unfortunately) assuming these are all already active. Thanks for pointing the above out!
     
    orionsyndrome and Bunny83 like this.
  8. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,572
    Yes, do that :)

    Note that Awake of an object is only called once in the lifetime of the object. I highly recommend to add a context reference to your Debug.Log call so you can identify the object by clicking on the log message in the console.

    Code (CSharp):
    1. Debug.Log("Workspot Awake", gameObject);
    You should never see Awake called twice for the same object.

    You just showed us that one single log message. What exactly made you think that the object somehow got cloned / copied? Do you actually see two Awake messages for the same object?
     
  9. Tom163

    Tom163

    Joined:
    Nov 30, 2007
    Posts:
    1,274
    Because I instantiate a known number of these objects, and I end up with exactly twice that number, half of which have "(Clone)" appended. My count variable also goes up to exactly twice the known number.

    After some more debugging, I believe this is an artifact of the procedural generation somehow. I'll dig through that asset's code to verify.