Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Deleting all chidlren of an object

Discussion in 'Scripting' started by EndlesNameles, Jun 12, 2011.

  1. EndlesNameles

    EndlesNameles

    Joined:
    Jun 11, 2011
    Posts:
    31
    Is there is any way to destroy all the children of an object? I would like it in C# if possible.
     
    guetta18 likes this.
  2. Ardan

    Ardan

    Joined:
    Oct 5, 2009
    Posts:
    68
    Something along these lines:
    Code (csharp):
    1.  
    2. Transform parent;
    3.  
    4. foreach(Transform child in parent) {
    5.     Destroy(child);
    6. }
    7.  
     
    emersondesign likes this.
  3. EndlesNameles

    EndlesNameles

    Joined:
    Jun 11, 2011
    Posts:
    31
    Hm it doesn't help too much
     
  4. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,327
    That code doesn't work. First of all, you can't destroy a Transform; you would need child.gameObject. But even with that, it won't work. Shawn White from UT gave me a good explanation, when I didn't understand what was happening:

    Here's one way to do it:
    Code (csharp):
    1. var children = new List<GameObject>();
    2. foreach (Transform child in transform) children.Add(child.gameObject);
    3. children.ForEach(child => Destroy(child));
     
  5. EndlesNameles

    EndlesNameles

    Joined:
    Jun 11, 2011
    Posts:
    31
    That looks great, I got the explanation, but can you put it in C# please :D
     
  6. JRavey

    JRavey

    Joined:
    May 12, 2009
    Posts:
    2,377
    He's basically creating a new collection, then iterating through that collection. It's pretty basic programming in itself, so I would recommend reading up on C# Lists (and other collections) as you're going to have to learn to love them for game programming.
     
  7. EndlesNameles

    EndlesNameles

    Joined:
    Jun 11, 2011
    Posts:
    31
    So children var should be a List type var?
     
  8. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,145
    That is C#.

    --Eric
     
    keenanwoodall, Mycroft and gdbjohnson like this.
  9. EndlesNameles

    EndlesNameles

    Joined:
    Jun 11, 2011
    Posts:
    31
    The variable declaration is done in JS way so I thought it all is.
     
    tmendez likes this.
  10. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,327
    I used var instead of List<GameObject> because the latter makes the code look redundant to me. Also, because I don't have an autocompleting IDE, I don't want to type it, either.
     
    iaroslav-titov likes this.
  11. EndlesNameles

    EndlesNameles

    Joined:
    Jun 11, 2011
    Posts:
    31
    I'm working on a 3D tile map editor, and I group my platforms in separated GameObjects. What I want to do is to make a delete all button so I can start all over with a new map, and when pressing a button, the objects in those GameObjects to be destroyed.
     
  12. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,145
    The variable declaration was done in a C# way, actually (since 3.0). Also JS uses for/in rather than foreach, and I don't think it has lambda expressions.

    --Eric
     
  13. Jessy

    Jessy

    Joined:
    Jun 7, 2007
    Posts:
    7,327
    UT calls this a lambda.

    Code (csharp):
    1. var children = List.<GameObject>();
    2. for (var child : Transform in transform) children.Add(child.gameObject);
    3. children.ForEach(function(child) Destroy(child));
    Using the ForEach doesn't look any better to me in JS:
    Code (csharp):
    1. children.ForEach(function(child) Destroy(child));
    2. for (var child in children) Destroy(child);
    but I usually prefer it in C#, though I don't really care for this simple example (var would make it shorter, but if I'm going to write a loop, I'll take the extra clarity of "GameObject"):
    Code (csharp):
    1. children.ForEach(child => Destroy(child));
    2. foreach (GameObject child in children) Destroy(child);
     
    Last edited: Jun 12, 2011
    ocimum likes this.
  14. EndlesNameles

    EndlesNameles

    Joined:
    Jun 11, 2011
    Posts:
    31
    I haven't even heard of lambdas, it's good I did now
     
  15. LBandy

    LBandy

    Joined:
    Jun 2, 2012
    Posts:
    2
    What about a way without allocating the memory for all the transforms?

    Code (csharp):
    1.             int childs = transform,.childCount;
    2.             for (int i = childs - 1; i > 0; i--)
    3.             {
    4.                 GameObject.Destroy(transform.GetChild(i).gameObject);
    5.             }
     
  16. Jumplegreen

    Jumplegreen

    Joined:
    Nov 1, 2012
    Posts:
    2
    what about - C#


    while(parent.transform.GetChildCount()>0){
    GameObject.Destroy(parent.transform.GetChild (0));
    }
     
    Last edited: Dec 11, 2012
    theolagendijk likes this.
  17. cpasjuste

    cpasjuste

    Joined:
    Apr 2, 2012
    Posts:
    139
    Hehe, it's a shame i didn't think it myself :)
     
  18. niebau

    niebau

    Joined:
    Aug 18, 2012
    Posts:
    3
    I doubt this will work.
    According to the reference manual, actual object destruction is always delayed until after the current Update loop.

    Your for condition is based on the assumption that GetChildCount() is decreased as soon as Destroy() is called.
    It's more likely, though, that this happens later during the actual object destruction.
    Thus your for condition will never be false, and you are caught in an endless loop.
     
  19. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,457
    Your post is based on the assumption it doesn't :)
     
  20. niebau

    niebau

    Joined:
    Aug 18, 2012
    Posts:
    3
    My post is based on the assumption that this thread is about finding a solid solution for destroying all children objects :).
    Using code that relies on implementation details of the framework doesn't sound like a good idea to me.

    LBandy's code snippet looks like a solid solution (although you would have to replace i>0 with i>=0 in the for condition, otherwise you're missing out on the first child node).
     
    Last edited: Mar 2, 2013
    aimozs likes this.
  21. Glaskows

    Glaskows

    Joined:
    Mar 14, 2013
    Posts:
    9
    If that is your concern, I think an easy and secure way to do it is reversing the iteration

    Code (csharp):
    1.        
    2. for ( int i=transform.childCount-1; i>=0; --i )
    3. {
    4.     var child = transform.GetChild(i).gameObject;
    5.     Destroy( child );
    6. }
    7.  
     
    Last edited: Mar 14, 2013
  22. IndieForger

    IndieForger

    Joined:
    Dec 31, 2012
    Posts:
    48
    Thanks a lot. Very useful thread. Took me some time to realize what I am doing wrong. I finally used one liner to do that as shown in below c# code
    Code (csharp):
    1. foreach (Transform childTransform in parentObj.transform) Destroy(childTransform.gameObject);
    Check this post for more details and JS code.
     
  23. MorphVGX

    MorphVGX

    Joined:
    Jun 21, 2010
    Posts:
    57
    You should not destroy something inside a collection you are cycling. Maybe Unity allows it with Destroy instead of DestroyImmediately(), but not a good practice nonetheless.
     
  24. kellanhiggins

    kellanhiggins

    Joined:
    Sep 11, 2013
    Posts:
    2
    Hey, I found a pretty simple solution:
    Code (csharp):
    1.  
    2.         Transform[] allTransforms = gameObject.GetComponentsInChildren<Transform>();
    3.  
    4.         foreach(Transform childObjects in allTransforms){
    5.             if(gameObject.transform.IsChildOf(childObjects.transform) == false)
    6.                 Destroy(childObjects.gameObject);
    7.         }
    8.  
     
  25. Jeff-Kesselman

    Jeff-Kesselman

    Joined:
    Apr 5, 2010
    Posts:
    85
    Its also works to loop backwards in cases like this

    Code (csharp):
    1.  
    2. for(int i=transform.childCount-1;i>=0;i--){
    3.     Destroy (transform.GetChild(i));
    4. }
     
    Last edited: Feb 17, 2014
  26. FamerJoe

    FamerJoe

    Joined:
    Dec 21, 2013
    Posts:
    193
    Perfect time to make a function in your ExtendedMethods class

    Code (csharp):
    1.  
    2.     public static void DestroyChildren(this GameObject go)
    3.     {
    4.        
    5.         List<GameObject> children = new List<GameObject>();
    6.         foreach (Transform tran in go.transform)
    7.         {      
    8.             children.Add(tran.gameObject); 
    9.         }
    10.         children.ForEach(child => GameObject.Destroy(child));  
    11.     }
    12.  
     
  27. HonorableDaniel

    HonorableDaniel

    Joined:
    Feb 28, 2007
    Posts:
    2,829
    Shouldn't it be a Transform extension (not GameObject)? And also you're creating a list which probly isn't good for the gc.
     
  28. rutter

    rutter

    Joined:
    Mar 21, 2012
    Posts:
    84
    Declaring a temporary collection does allocate heap memory, which can be problematic when deleting many children (or deleting them often).

    In some quick testing, this is about twice as fast as the list-based solution I usually see posted and allocates no heap:

    Code (csharp):
    1.     public static void DestroyChildren(this Transform root) {
    2.         int childCount = root.childCount;
    3.         for (int i=0; i<childCount; i++) {
    4.             GameObject.Destroy(root.GetChild(0).gameObject);
    5.         }
    6.     }
    I cache the child count because I've seen it fail to update during the destroy loop, which could cause problems.
     
  29. FamerJoe

    FamerJoe

    Joined:
    Dec 21, 2013
    Posts:
    193
    Why?
     
  30. HonorableDaniel

    HonorableDaniel

    Joined:
    Feb 28, 2007
    Posts:
    2,829
    Because children/parent is a Transform concept, not GameObject.
     
  31. FamerJoe

    FamerJoe

    Joined:
    Dec 21, 2013
    Posts:
    193
    Ah, I prefer to work with game objects personally since at the end of the day you are destroying GameObjects.
     
  32. HonorableDaniel

    HonorableDaniel

    Joined:
    Feb 28, 2007
    Posts:
    2,829
    Well just for consistency, I would put it on Transform. You have transform.parent, transform.childCount, transform.DetachChildren(). It's not gameObject.parent, gameObject.DetachChildren() you know.

    And I noticed your calling GameObject.Destroy(), why?? Destroy is declared on Object and for clarity Object.Destroy() is the method that should be called. GameObject.Destroy() is not documented and most likely calls Object.Destroy() anyways.
     
  33. FamerJoe

    FamerJoe

    Joined:
    Dec 21, 2013
    Posts:
    193
    Yeah, idk, I just took some of the code from earlier in the thread and made it into an extension method. Wasn't really considering much else than "it works". :) I like rutter's suggestion though.
     
  34. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    12,042
    Which is a reasonable assumption given that the entire reason this is being looked at is that the original approach couldn't modify the collection it was enumerating over - the collection does get modified immediately. I'd also be reasonably confident that this isn't an implementation detail that will change, since it's a rather fundamental one for many things (eg: you'd otherwise potentially have to check that things aren't in the deletion queue yourself at times).
     
    Last edited: Apr 24, 2014
  35. TooT

    TooT

    Joined:
    Feb 19, 2014
    Posts:
    1
    How about this?

    while(parent.transform.GetChildCount()>0){
    Transform child = parent.transform.GetChild (0);
    child.parent = null;
    Destroy(child.gameObject);
    }
     
    Xinzz likes this.
  36. frogsbo

    frogsbo

    Joined:
    Jan 16, 2014
    Posts:
    79
    thanks for that. to recap:

    in JS:

    Code (csharp):
    1.          var childs : int = go.transform.childCount;
    2.  
    3.         for (var i = childs - 1; i >= 0; i--)
    4.         {
    5.             Destroy(go.transform.GetChild(i).gameObject);
    6.             }
    7.  
    in C:
    Code (csharp):
    1.  
    2.      int childs = transform,.childCount;
    3.  
    4.         for (int i = childs - 1; i > 0; i--)
    5.  
    6.         {
    7.  
    8.             GameObject.Destroy(transform.GetChild(i).gameObject);
    9.  
    10.         }
     
  37. tiagoroldao

    tiagoroldao

    Joined:
    Dec 9, 2013
    Posts:
    4
    The loop should go from size-1 to 0, so
    Code (csharp):
    1. for (var i = childs - 1; i >= 0; i--)
     
  38. naked_chicken

    naked_chicken

    Joined:
    Sep 10, 2012
    Posts:
    186
    It actually doesn't matter which direction the loop goes. Destroy doesn't actually destroy the object. It queues it up to be destroyed so the object will be safe while you're in this loop. Also why you can't use a while loop. If you were to use DestroyImmediate then it would be a different story, but DestroyImmediate is slower.
     
    Mycroft, Anisoropos and Gru like this.
  39. frogsbo

    frogsbo

    Joined:
    Jan 16, 2014
    Posts:
    79
    counting loops backwards is mostly useful when you are deleting or changing the end values and resizing etc.

    For childs loop, There is something very interesting to know about the loop numbers....

    child 0 if always the parent transform... Afterwards, if the parent has 4 children the 4 children will be array 1-4... and is each 4 has 4, the next 16 values in array will be 3rd level children.
     
  40. Shadowphax

    Shadowphax

    Joined:
    Jul 26, 2013
    Posts:
    8
    You are correct. I tried this and it doesn't work for what looks exactly like the reason you describe. Unity does not get a chance to actually destroy the children and childCount never actually decrements.
     
    Mycroft likes this.
  41. Mode_Six

    Mode_Six

    Joined:
    Feb 16, 2014
    Posts:
    4
    I've found a quite simple solution that doesn't rely on using a list to delete the child objects.

    Works wonderfully.

    Code (csharp):
    1.  
    2.     public GameObject parentGO;
    3.  
    4.     void DeleteAllChildren()
    5.     {
    6.         foreach (Transform child in parentGO.transform)
    7.         {
    8.             Destroy(child.gameObject);
    9.         }
    10.     }
    11.  
    You can either set the parent GameObject in the inspector or you can programatically find it using whichever method you desire.
     
    Last edited: Feb 28, 2015
    shaneparsons, srmols and rentox like this.
  42. TimK_personal

    TimK_personal

    Joined:
    Jul 30, 2014
    Posts:
    18
    Interesting... presumably the transform is not invalidated until the gameobject is reaped, so iterating the loop is safe.
     
  43. Viltro

    Viltro

    Joined:
    Oct 11, 2013
    Posts:
    3
    I am a little confused. I came here because I seem to have a similar issue as this thread. However, according to the docs: "If obj is a GameObject it will destroy the GameObject, all its components and all transform children of the GameObject." calling GameObject.Destroy( objMyGameObject) will take down objMyGameObject and all child transforms for you so why do we need to iterate over all child transforms deleting them? I ask because I seem to have a GameObject "leak". I was looking to see if it was necessary to delete all children or do they just get orphaned which would explain my "leak".
     
  44. blizzy

    blizzy

    Joined:
    Apr 27, 2014
    Posts:
    775
    To keep the parent, not destroy it.
     
  45. mwk888

    mwk888

    Joined:
    Jan 26, 2014
    Posts:
    16
    There are good solutions above, but thought I'd post my utility. This also detaches the children immediately so the transform childCount is zero post-call. (I don't like leaving the deleted GameObject references in the parent transform until Unity cleans up as they're dead objects.)

    Like some solutions above this loops backwards through the child index; that isn't actually necessary with current Unity runtime because the child removal from the transform is deferred, but it seems the better pattern.

    Code (CSharp):
    1.         /// <summary>
    2.         /// Calls GameObject.Destroy on all children of transform. and immediately detaches the children
    3.         /// from transform so after this call tranform.childCount is zero.
    4.         /// </summary>
    5.         public static void DestroyChildren(Transform transform) {
    6.             for (int i = transform.childCount - 1; i >= 0; --i) {
    7.                 GameObject.Destroy(transform.GetChild(i).gameObject);
    8.             }
    9.             transform.DetachChildren();
    10.         }
     
    SimRuJ, Nition, Dexer75 and 1 other person like this.
  46. TimK_personal

    TimK_personal

    Joined:
    Jul 30, 2014
    Posts:
    18
    Good idea on the addition of DetachChildren. I will add that to our internal implementation of this. May I humbly suggest that this is a great candidate for an extension method?
     
  47. Philipp_Programmer_Germany

    Philipp_Programmer_Germany

    Joined:
    Apr 8, 2015
    Posts:
    9
    Here an example code:
    Code (CSharp):
    1. // Not tested but it have to work
    2. for(int i = transform.childCount -1; i <= 0; i--)
    3. {
    4.         GameObject.Destroy(transform.GetChild(i).gameObject);
    5. }
    6.  
    7. // or as a function waith any GameObject
    8. [private, protected, public] void DeleteAllChilds(GameObject pObj)
    9. {
    10.        if(pObj  != null)
    11.        {
    12.               for(int i = pObj.transform.childCount -1; i <= 0; i--)
    13.               {
    14.                       GameObject.Destroy(pObj.transform.GetChild(i).gameObject);
    15.               }
    16.         }
    17.         else Debug.LogError("GameObject does not exist anymore!");
    18. }
     
  48. gdbjohnson

    gdbjohnson

    Joined:
    Dec 16, 2014
    Posts:
    40
    I'm noticing a lot of code destroying objects in a set, while iterating over it. While this may work now, it seems risky to me. If Unity's background processes / GC update the set in the middle of your iteration, the logic will break, won't it? Jessy's solution seems to be more correct to me. Is there a guarantee that the set will not be changed during the iteration?

    Great addition to add in DetachChildren() after calling Destroy(). I got caught by this once.
     
  49. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,145
    That's not something that can happen; GameObjects are only removed at the end of the frame. Also, scripting doesn't use threads.

    --Eric
     
    gdbjohnson likes this.
  50. Gru

    Gru

    Joined:
    Dec 23, 2012
    Posts:
    138
    This code doesn't work, it only removes the first child - flags it for deletion several times. All of these solutions are overengineered based on bad presumptions.

    DestroyImmediate should not be called at runtime, only in the editor.