使用 foreach 循环查找作为其他对象的子对象的游戏对象 (Unity3d)

Using foreach loop to find GameObjects that are children of something else (Unity3d)

我正在制作视频游戏,虽然我有通用 C# 的现有代码,但我现在必须将其移至 Unity。我对通用 C# 有一些基础知识,但我才刚刚开始学习 Unity 编码方式。

首先,我想编写一个代码,将所有游戏区域定位到正确的位置,然后将它们隐藏。是的,不要惊讶,他们需要都在同一个地方。

区域可以有三种尺寸选择,我称之为小、中、大。大小区都得手动写

 List <GameObject> SmallAreas = new List<GameObject>();

void DefineSmallAreas()
{
    SmallAreas.Add(areaConfirmLoad);
    SmallAreas.Add(areaConfirmQuit);
    SmallAreas.Add(areaConfirmSave);
    SmallAreas.Add(areaGameSaved);
    SmallAreas.Add(areaSave);
    SmallAreas.Add(areaLoad);   
}

大面积也一样

现在其他地区都是中等的,而且数量很多。

所以,我想遍历 "areaContainer" 的所有子游戏对象,检查它们的名称是否以 "area" 开头,如果是,我想将它们添加到 MediumAreas 列表。

我就是这样试的:

void DefineMediumAreas()
{
    GameObject areaContainer = GameObject.Find("areaContainer");

    foreach (GameObject thisObject in areaContainer)
    {
        char[] a = thisObject.Name.ToCharArray();
        if (a.Length >= 4)
        {
        char[] b = { a[0], a[1], a[2], a[3] };
        string thisObjectType = new string(b);
                        (if (thisObjectType == "area")&&(!(SmallAreas.Contains(thisObject))
                        &&(!(LargeAreas.Contains(thisObject)))
                        {
                            MediumAreas.Add(thisObject);
                        }
    }   
}

然而,这显示了一个错误,即 "areaContainer" 不能那样使用,我现在无法访问 Unity,因此无法复制确切的消息。我认为它类似于 "Gameobject doesn't have IEnumerator".

我确实尝试 google 以获得更好的方法,并找到了一个叫做 "transform" 的东西。

 foreach(Transform child in transform)
 {
     Something(child.gameObject);
 }

我不明白的是如何在我的具体情况下使用这个 "transform"。

如果这个问题很傻,请不要生我的气,我是Unity的新手,必须从头开始学习。

还有一个小的第二个问题。这个把对象变成隐形的工作能行吗:

    foreach(GameObject thisObject in MediumAreas)
    {
        thisObject.position = MediumVector;
        thisObject.GetComponent<Renderer>().enabled = false;
    }

MediumVector 是对象必须移动到的位置,它似乎在工作。

有多种方法可以解决您的问题。其中之一是使用 Tags。只需用一些标签标记您的 MediumArea 预制件,然后您就可以找到所有带有 FindGameObjectsWithTag(string) (Unity Docs) 标记的游戏对象。然后你可以像这样填充你的collection:

MediumAreas.AddRange(FindGameObjectsWithTag("MediumArea"));

第二种方法可能是找到所有具有相同附加脚本 FindObjectsOfType<T>() (Unity Docs) 的 objects。这在您搜索相同类型的实例时很有用,例如 Medium Area.

假设您有一个 Area 脚本

public class Area : MonoBehaviour {
    public AreaSize Size;    // AreaSize is Enum
}

然后您可以简单地找到您的区域,例如:

var allAreas = FindGameObjectsOfType<Area>();
var mediumAreas = allAreas.Where(e => e.Size == AreaSize.Medium); // using System.Linq;

可以这样做:foreach(Transform child in transform)

因为 Transform class 实现了 IEnumerable 并且有一些机制可以让您使用 foreach 循环访问子游戏对象。


很遗憾,您不能这样做:foreach (GameObject thisObject in areaContainer)

因为 areaContainerGameObject 并且此实现未针对 GameObject class 完成。这就是您收到此错误的原因:

foreach statement cannot operate on variables of type 'UnityEngine.GameObject' because 'UnityEngine.GameObject' does not contain a public definition for 'GetEnumerator'

要修复它,请在找到 GameObject:

后将循环更改为使用 Transform
GameObject areaContainer = GameObject.Find("areaContainer");
foreach (Transform thisObject in areaContainer.transform){}

完整代码:

List<GameObject> MediumAreas = new List<GameObject>();

void DefineMediumAreas()
{
    GameObject areaContainer = GameObject.Find("areaContainer");
    foreach (Transform thisObject in areaContainer.transform)
    {
        //Check if it contains area
        if (thisObject.name.StartsWith("area"))
        {
            //Add to MediumAreas List
            MediumAreas.Add(thisObject.gameObject);
        }
    }
}

您想访问 "areaContainer"

的所有子游戏对象

void DefineMediumAreas()函数中,需要Transform[]得到子数组。使用这个:

Transform[] areaContainer = GameObject.Find("areaContainer").GetComponentsInChildren<Transform>();

foreach(Transform thisTransform in areaContainer)
{
  ...
}

希望对你有帮助

我创建了一个项目来回答你的问题,最终结果是这样的:

如您所见,我创建了一个名为 "areaContainer" 的游戏 object 并添加了 3 个 children,其名称分别为:"area01"、"area02" 和"anotherObject".

设法获取所有以 "area" 开头的 "areaContainer" children 的脚本如下所示:

public GameObject areaContainer;
public List<GameObject> MediumAreas = new List<GameObject>();

private void Start()
{
    DefineMediumAreas();
}

void DefineMediumAreas()
{
    for (int i = 0; i < areaContainer.transform.childCount; i++)
    {
        var childGameObject = areaContainer.transform.GetChild(i).gameObject;
        if (childGameObject.name.StartsWith("area"))
            MediumAreas.Add(childGameObject);
    }
}

1- 我最终在脚本中引用了 areaContainer object 而不是使用 GameObject.Find,因为它的性能更高。

2- 要获得游戏 object 的 child,您需要访问其转换并调用 GetChild(index)。因此,通过迭代 parent 容器,即 "areaContainer",我们得到它的 childCount.

3- 要检查名称是否以 "area" 开头,只需使用 .StartsWith("area") 其中 return true 或 false.


对于第二个问题,您可以隐藏 object 禁用渲染器或停用它 (thisObject.SetActive(false);

希望对您有所帮助;编码愉快!