Search Unity

Intended behaviour when changing parent of dontdestroyonload gameobject to null

Discussion in 'Scripting' started by BoaNeo, Apr 3, 2020.

  1. BoaNeo

    BoaNeo

    Joined:
    Feb 21, 2013
    Posts:
    56
    I ran into an annoying issue where objects instantiated in a scene suddenly popped up in DontDestroyOnLoad even though that method was never called on those game objects.

    The problem turned out to be that these objects were briefly parented to a node in DontDestroyOnLoad and when set "back" to the main scene with SetParent(null) they remained in DontDestroyOnLoad - apparently you have to assign a non-null parent to clear this.

    Add this this to test:

    DontDestroyOnLoad(this);
    GameObject go = new GameObject();
    go.transform.SetParent(this.transform);
    go.transform.SetParent(null);

    'go' will remain in DontDestroyOnLoad

    So, I can work around this, obviously, but was wondering if it's a bug or intended behaviour? I would find it a bit odd if it was the latter, but I can accept that there might be deeper technical reason why it has to be that way even if it's not exactly obvious.
     
    BeorGames and PraetorBlue like this.
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    That is a very interesting edge case... nice detective work. I never thought there was a way to un-DontDestroyOnLoad something (except to Destroy it manually obviously).

    But if I read your post above correctly, but you're saying that if I mark something as DDOL, then parent it to a non-DDOL object, the DDOL bit falls off? I could see that being useful ... maybe, plus it kinda makes sense since you cannot mark non-root objects as DDOL.
     
  3. spilat12

    spilat12

    Joined:
    Feb 10, 2015
    Posts:
    38
    Hear ye, hear ye! I think that this info should be in the documentation?

    It turns out that when a DDOL game object is parented to another game object, it exits the whole DDOL thing. In fact, if you look at your Hierarchy window at play time, you will see the DontDestroyOnLoad dropdown that lists all DDOL objects. As soon as a DDOL object is parented to anything else, it is removed from that list and doesn't return there, so if you have to add it to DDOL list again.

    It all makes sense now.
     
  4. FargleBargle

    FargleBargle

    Joined:
    Oct 15, 2011
    Posts:
    774
    I had the exact opposite problem: My player was marked as DontDestroyOnLoad, but if I temporarily parented him to anything before changing scenes, he wouldn't return to the DontDestroyOnLoad group when released, and got destroyed along with the rest of the scene. The DontDestroyOnLoad attribute only gets looked at when the code is read - either in Awake() or Start() usually. The object is moved to the DontDestroyOnLoad group... and then it's on its own. If it leaves the group at any point, the DontDestroyOnLoad attribute is NOT persistent. You must actively move it back into the group every time or it will meet an untimely end the next time the scene changes.

    It would be nice if it could be permanently tagged as persistent, no matter where it is when the scene changes. In the mean time, after setting the parent to null, I add DontDestroyOnLoad(playerGO); which buys him readmission to the chosen ones after straying from the group.
     
    Last edited: Oct 13, 2020
    Fressbrett likes this.
  5. blobface

    blobface

    Joined:
    Mar 6, 2019
    Posts:
    12
    Glad I'm not alone on this, it's particularly annoying in VR given quite often anything you've grabbed is childed to your controller rig, and if you decide the rig is DDOL, then anything you've picked up (and let go)* in the world loads with you to the next scene by default... it's extremely bizarre this is a thing.

    *added (and let go) for clarity
     
    Last edited: Jan 8, 2021
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    On the other hand, making Katamari Damacy clones is easier.
     
  7. blobface

    blobface

    Joined:
    Mar 6, 2019
    Posts:
    12
    lol true, except in this case, anything you've picked up and let go comes with you too...!
     
  8. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    Yeah, that is nutty. I didn't believe you but I just tested it and you're completely right... DDOL is "sticky." Seems like a good footnote for Unity to put in their DDOL docs!
     
    blobface likes this.
  9. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    "DontDestroyOnLoad" is just a Scene that doesn't get destroyed when another Scene is loaded. As such, that DontDestroyOnLoad "list" is in fact a whole Scene in its own right, created implicitly when needed. Once you understand that, all of the same rules about moving objects between scenes and (un)parenting them can be applied consistently. It's kind of an elegant system, but they just leave us to figure it out ourselves.

    When you call SetParent() on a Transform, if the parent Transform is in another Scene the child is moved to that Scene as well, taking all children with it. Calling DontDestroyOnLoad() on something just moves that object and all of its children to that implicitly created scene.

    And, importantly, a scene change is never required to un-parent something - it always just gets made a root level object in its current Scene. So if you DDOL an object and then un-parent a child, that child becomes a root level object in the DontDestroyOnLoad scene.

    This makes complete sense if you know it's a Scene, which the documentation doesn't even seem to mention. I completely agree that the documentation could clear it up in not much longer than it took me to write this post. :)

    Given the above, you should be able use SceneManager.MoveGameObjectToScene(...). I say "should" because I've never tried it.

    This does make me wonder, though... what happens if you call DDOL on a non-root object? It doesn't make design sense to me, so I don't think I've ever done it, but now I'm interested to see what Unity does. Will it de-parent it, complain at me, also move the root parent, or something else? This is also not explained in the docs.
     
    blobface likes this.
  10. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Well, question answered, and this also isn't in the docs page:
    upload_2021-1-8_14-0-16.png
     
    Bunny83 likes this.
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    Well penguin? We're all waiting! :)
     
  12. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Well, I can't dissapoint my fans now, can I? ;)

    The following code successfully moves something back to the active Scene, where it does get destroyed when that Scene in unloaded:
    Code (csharp):
    1. UnityEngine.SceneManagement.SceneManager.MoveGameObjectToScene(gameObject, UnityEngine.SceneManagement.SceneManager.GetActiveScene());
    Checked by:
    1. Created two scenes. One of those scenes had an object with scripts which mark it as DDOL in Start(), and calls the above code if the 'U' key is pressed.
    2. Another script in each scene swaps to the other scene if space is pressed.
    3. Ran the scenes. Swapped back and forth a bunch of times, verifying that a bunch of the above objects appeared in a "DontDestroyOnLoad" Scene shown in the Hierarchy.
    4. Pressed 'U' and verified that they were no longer in the "DontDestroyOnLoad" Scene, and were in the other normal scene.
    5. Swapped scenes again. Verified that the objects had in fact been destroyed - no longer in the hierarchy at all.

    So yes, it's a fairly elegant system, poorly documented.
     
    Hamza-EG likes this.
  13. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    Thanks Penguin! I think if it didn't work that way I would lose faith in the consistency of the entire universe.

    Thank you for helping me maintain my delicate illusion.

    (Seriously though, it's cool that it makes sense in the way it works!!)
     
    angrypenguin likes this.
  14. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    Haha, that's a part of why I hadn't been bothered testing it for myself. It looks like a Scene, it quacks like a Scene... it's a Scene! Right..?
     
  15. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,726
    Do Angry Penguins quack or is it some other noise?

    Again though, I never again have to forget how DDOL works, especially because you SEE that scene anytime you dig through your running game (always!!).

    Man, I love Unity3D...
     
  16. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,620
    It's a gentle thunder of Cherry Browns thwacking home. ;)
     
    Kurt-Dekker likes this.
  17. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,998
    Just want to add that DDOL did work like that even before we had multi scene editing. I guess that they switched the "flag" it was before to just being a seperate hidden scene. I guess once you have the multiscene thing done, this was an easy switch.

    Though as far as I remember, parenting a non DDOL object to a DDOL object and unparent it again in the past, did not preserve the flag. So in the past I think the flag was stuck to the actual gameobject. However parenting a DDOL object to a non DDOL object did also clear that flag as it only works for root object anyways.
     
    Kurt-Dekker likes this.
  18. dohaiha930

    dohaiha930

    Joined:
    Mar 27, 2018
    Posts:
    55
    Same issue here. SetParent(null), then this gameobject automatic set to DDOL.
    And Unity don't even say about it. :rolleyes:
     
  19. Bunny83

    Bunny83

    Joined:
    Oct 18, 2010
    Posts:
    3,998
    There is no real issue here. If the gameobject is located in the DDOL scene before you unparent it, it won't automatically move to a different scene. What if you have multiple scenes loaded additively? Where should the sub object go once you unparent it? Of course it stays in the DDOL scene where it's currently located. You can use SceneManagement.SceneManager.MoveGameObjectToScene to move a gameobject to a certain target scene. However, as we already discussed in thie thread, parenting the object to a different object that lives in your target scene and then unparent it, will also move the object to that target scene.
     
  20. dohaiha930

    dohaiha930

    Joined:
    Mar 27, 2018
    Posts:
    55
    But on older version not have this issue. Document of Unity is not mention it. It is all we discussing.