How to loop through and destroy all children of a game object in Unity?

Viewed 34982

I have the following script which is attached to a game object and run when I click a button in the editor:

public void ClearChildren() {
    Debug.Log(transform.childCount);
    float i = 0;
    foreach (Transform child in transform) {
        i += 1;
        DestroyImmediate(child.gameObject);
    }
    Debug.Log(transform.childCount);
}

It shows that the original childCount is 13 and the final value is 6. Furthermore, if I print out all i each iteration I see the values 0-6, showing that the loop only runs 7 times, not 13 as expected.

How can I delete all the children such that the final value is 0? For reference, the children I'm trying to delete were automatically created by a vendor script. I'm also running this script in [ExecuteInEditMode] for what it's worth.

The following script has the same behavior; if the childCount starts at 4 then it ends at 2:

public void ClearChildren() {
    Debug.Log(transform.childCount);
    for (int i = 0; i < transform.childCount; i++) {
        Transform child = transform.GetChild(i);
        DestroyImmediate(child.gameObject);
    }
    Debug.Log(transform.childCount);
} 

If I try the following I get a runtime error pointing to the foreach line saying "InvalidCastException: Cannot cast from source type to destination type."

public void ClearChildren() {
    Debug.Log(transform.childCount);
    foreach ( GameObject child in transform) {
        DestroyImmediate(child);
    }
    Debug.Log(transform.childCount);
}
4 Answers

The other solutions here seem over-engineered. I wanted something with a smaller code footprint. This destroys the immediate children of an object, and all of their descendents.

while (transform.childCount > 0) {
    DestroyImmediate(transform.GetChild(0).gameObject);
}

The problem is that you are trying to remove the Object in the for loop while accessing them.

Here is what you should do:

  1. Find all Child objects and store them in an array

  2. Destroy them in another loop

     public void ClearChildren()
     {
         Debug.Log(transform.childCount);
         int i = 0;
    
         //Array to hold all child obj
         GameObject[] allChildren = new GameObject[transform.childCount];
    
         //Find all child obj and store to that array
         foreach (Transform child in transform)
         {
             allChildren[i] = child.gameObject;
             i += 1;
         }
    
         //Now destroy them
         foreach (GameObject child in allChildren)
         {
             DestroyImmediate(child.gameObject);
         }
    
         Debug.Log(transform.childCount);
     }
    

Are all the children direct childrens of your parent object?

I believe the foreach(Transform child in transform) will only loop through the children that are in the first level after the parent. So if there are objects that are childrens of a child of a parent they wont be looped. Parent -> Child1 -> Child2 (child of Child1). Hope its undestandable what i mean.

To also get the childrens in second level and forth i would use:

Transform[] allChildren = GetComponentsInChildren<Transform>(true);

And then loop through this list to destroy them (As pointed out by Programmer):

The problem is that you are trying to remove the Object in the for loop while accessing them.

Use Destroy instead of DestroyImmidiate. Unless you have some reason for using the latter. The reason you can't loop through the children is because DestroyImmidiate deletes them ASAP while Destroy waits until the end of the frame. ASAP will happen sometime in the middle of your loop so your indexes get all messed up. If you do actually need to destroy them before the end of the frame, try this:

while (transform.childCount > 0) 
{
    DestroyImmediate(transform.GetChild(0).gameObject);
}
Related