从列表中获取Unity3d,只获取特定组件类型的实体

时间:2014-09-24 10:29:39

标签: c# generics unity3d

我知道如果我有像

这样的东西
Component tmp = (myClass)gameObject.GetComponent<myClass>();

可以返回null值,也可以返回类型为&#34; myClass&#34;的实例。如果它存在于我的特定游戏对象上。现在,让我们假设我有一个来自给定半径的物理球体捕获的对象数组。我有20个游戏对象返回。

如何创建一个例程来仅返回那些具有组件的游戏对象,这样我就不必一遍又一遍地编写自己的迭代器。再次成为泛型,因为在一个领域我可能想要另一个和另一个地方。我不想全身心地进行类型转换,以使可读性变得痛苦。

反馈(按照Ciprian的回答)

我逐字尝试了你的方法,并没有得到任何&#34; Class&#34;我想要它即使它是一个附加组件。所以,我试着略微修改例程。首先,确保一个合适的游戏对象&#34;。然后,尝试拨打GameObject's .GetComponent<T>()。但这导致错误,即使<T>与我通过get Component寻找的类型相同。

public static IEnumerable<T> GetItemsAsT<T>(this object[] objects) 
        where T:class
    {
        GameObject gObj;
        foreach(var obj in objects)
        {
            if( obj is GameObject )
            {
                gObj = (GameObject)obj;
                if( gObj.GetComponent<T>() != null )
                {
                    Debug.Log ( "Found via IEnumerable" );
                    yield return gObj.GetComponent<T>();
                }
            }
        }
        yield break;
    }

对Ciprian的回答略有修改。

Error CS0311: The type 'T' cannot be used as type parameter 'T' in the generic type or method 'UnityEngine.GameObject.GetComponent<T>()'. There is no implicit reference conversion from 'T' to 'UnityEngine.Component'. (CS0311) (Assembly-CSharp)

2 个答案:

答案 0 :(得分:1)

我知道你需要两个可以实现对象数组的代码案例:

static class GenericUtils
{
    public static IEnumerable<T> GetItemsAsT<T>(this object[] objects) 
    where T:class
    {
        foreach(var obj in objects)
        {
            var t = obj as T;
            if(t != null)
                yield return t;
        }
        yield break;
    }
    public static IEnumerable<T> GetItemsWhere<T>(this object[] objects, Predicate<T> predicate) 
        where T:class
    {
        foreach(var tObj in objects.GetItemsAsT<T>())
        {
            if(predicate(tObj))
            {
                yield return tObj;
            }
        }
        yield break;
    }
}

要使用它们,您可以让我们说出一个圆圈列表:

items.GetItemsAsT<Circle>();

或使用谓词来过滤它们:

items.GetItemsWhere<Circle>(c => c.Radius < 30);

所有项目都是IEnumerable,因此如果您需要将它们转换为数组,请使用.ToArray(),或将它们用作List使用.ToList()

<强>后来 如果你熟悉Linq,你可以只使用第一种方法,然后使用Linq组合函数,这样你可以重写最后一行代码:

items.GetItemsAsT<Circle>().Where(c => c.Radius < 30);

此外,如果您的名字GetItemsAsT很详细,请为它们选择一个较短的名称:AsT。

答案 1 :(得分:1)

现在我觉得我理解你的问题,所以这就是我作为一个单独答案发布的原因。

您有一个复合对象,并且您希望根据游戏对象中存在的自定义类“属性”的混合来调用自定义操作。

public static IEnumerable<T> GetItemsAsT<T>(this GameObject[] objects) 
    where T:UnityEngine.Component
    {
        foreach(var obj in objects)
        {
            var t = obj.GetComponent<T>();
            if(t != null)
                yield return t;
        }
        yield break;
    }

我更新了更改并从您的答案中删除了不必要的演员表。问题的唯一重要变化是:

  • 使用GameObject []数组不能手动制作你的演员阵容

  • 使用T:Component而不是T:class