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

本文关键字:组件 类型 实体 获取 列表 Unity3d | 更新日期: 2023-09-27 18:24:07

我知道如果我有类似的东西

Component tmp = (myClass)gameObject.GetComponent<myClass>();

可以返回null值,也可以返回类型化的"myClass"的实例(如果它存在于我的特定游戏对象上)。现在,让我们假设我有一个给定半径的物理球体捕获的对象阵列。我已经归还了20件游戏物品。

我怎么能创建一个例程,只返回那些有组件的游戏对象,这样我就不必一遍又一遍地编写自己的迭代器了。再次成为泛型,因为在一个领域,我可能想要另一个地方。我不想为了提高可读性而到处乱丢类型转换。

反馈(根据Ciprian的回答)

我逐字逐句地尝试了你的方法,但没有得到任何我想要的"类",即使它是一个附加组件。所以,我试着稍微修改一下程序。首先,确保一个合适的"游戏对象"。然后,尝试调用GameObject's .GetComponent<T>()。但这会导致错误,即使<T>与我通过getComponent查找的类型相同。

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)

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

现在我想我理解了你的问题,所以这就是为什么我把它作为一个单独的答案发布。

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

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:组件而不是T:类

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

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。