简体   繁体   English

如何在 Unity 中循环并销毁游戏对象的所有子对象?

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

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.它显示原始childCount为 13,最终值为 6。此外,如果我在每次迭代中打印出所有i ,我会看到值 0-6,这表明循环仅运行 7 次,而不是预期的 13 次。

How can I delete all the children such that the final value is 0?如何删除所有子级以使最终值为 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.我还在[ExecuteInEditMode]中运行这个脚本,以实现它的价值。

The following script has the same behavior;以下脚本具有相同的行为; if the childCount starts at 4 then it ends at 2:如果childCount从 4 开始,那么它在 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."如果我尝试以下操作,我会收到指向foreach行的运行时错误,说“InvalidCastException:无法从源类型转换为目标类型。”

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

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.问题是您在访问它们时试图删除 for 循环中的对象。

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.我相信 foreach(Transform child in transform) 只会遍历父级之后第一级的子级。 So if there are objects that are childrens of a child of a parent they wont be looped.因此,如果有对象是父对象的子对象,则它们不会被循环。 Parent -> Child1 -> Child2 (child of Child1).父级 -> Child1 -> Child2(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.问题是您在访问它们时试图删除 for 循环中的对象。

Use Destroy instead of DestroyImmidiate .使用Destroy而不是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.您不能循环遍历子项的原因是因为DestroyImmidiate会尽快删除它们,而Destroy会等到帧结束。 ASAP will happen sometime in the middle of your loop so your indexes get all messed up. ASAP 将在您的循环中间的某个时间发生,因此您的索引会变得一团糟。 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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM