首页 > 解决方案 > 只初始化一次变量,而函数多次调用自己

问题描述

这个函数多次调用自己——找到一个游戏对象的子对象,然后再次将该对象传递给它自己。

我想返回遍历时找到的游戏对象列表。我无法在函数本身中初始化列表,因为我只需要初始化一次。当多次调用它时,它将重新初始化。

关于如何获取已获取对象列表的任何想法?

public static List<GameObject> FindAllGameObjectsInGameObject<T>(GameObject gameObjectToTraverse)
    {
        List<GameObject> list;
        
        

        foreach (Transform child in gameObjectToTraverse.transform)
        {
            if (list == null)
            {
                list = new List<GameObject>();
            }
            list.Add(child.gameObject);
            FindAllGameObjectsInGameObject<T>(child.gameObject);
        }
       

    }

标签: c#unity3d

解决方案


与其自己做递归,为什么不简单地使用GameObject.GetComponentsInChildren

返回 GameObject 或其任何子对象中 Type 类型的所有组件。

Unity 在子游戏对象上递归搜索组件。这意味着它还包括目标 GameObject 的所有子 GameObject,以及所有后续子 GameObject。

并做例如

using System.Linq;

接着

public static List<GameObject> FindAllGameObjectsInGameObject(GameObject gameObjectToTraverse)
{
    // This already gives you ALL transform components anywhere nested 
    // under the given object including inactive and disabled ones
    // INCLUDING the given object itself
    var allChildTransforms = gameObjectToTraverse.GetComponentsInChildren<Transform>(true);
    // This uses Linq to rather get all the according GameObjects 
    // See https://docs.microsoft.com/dotnet/api/system.linq.enumerable.select
    var allChildGameObjects = allChildTransforms.Select(t => t.gameObject);
    // Optional if you don't want to return the original given object itself
    // See https://docs.microsoft.com/dotnet/api/system.linq.enumerable.where
    var onlyChildGameObjects = allChildGameObjects.Where(c => c!= gameObjectToTraverse);

    return onlyChildGameObjects.ToList();
}

忘记递归,因为 Unity 已经为你做了它;)


那么实际上泛型参数是做什么T用的呢?您可能想在第一次通话中使用它

var allChildComponents = gameObjectToTraverse.GetComponentsInChildren<T>(true);

为了宁愿只获得具有T附加类型组件的对象。


只是为了实际回答您的尝试:您可以使用可选参数,例如

public static List<GameObject> FindAllGameObjectsInGameObject(GameObject gameObjectToTraverse, List<GameObject> list = new List<GameObject>())
{     
    foreach (Transform child in gameObjectToTraverse.transform)
    {
        list.Add(child.gameObject);
        FindAllGameObjectsInGameObject(child.gameObject, list);
    }
}

所以当你第一次调用它时,你就这样做

var objs = FindAllGameObjectsInGameObject(objectToTraverse);

在这种情况下,会自动创建一个新列表作为第二个参数。然后它在递归调用中在内部传递。

或者你可以稍微混淆一下,然后简单地将这两者分开:

public static List<GameObject> FindAllGameObjectsInGameObject(GameObject gameObjectToTraverse)
{
    return FindAllGameObjectsInGameObjectInternal(objectToTraverse, new List<GameObject>());
}

private static List<GameObject> FindAllGameObjectsInGameObjectInternal(GameObject gameObjectToTraverse, List<GameObject> list)
{     
    foreach (Transform child in gameObjectToTraverse.transform)
    {
        list.Add(child.gameObject);
        FindAllGameObjectsInGameObjectInternal(child.gameObject, list);
    }
}

但是,使用可选参数解决方案,您可以让开发人员有机会重用已经存在的列表,而不是每次都创建一个新列表;)


推荐阅读