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)
现在我想我理解了你的问题,所以这就是为什么我把它作为一个单独的答案发布。
您有一个复合对象,并且希望基于游戏对象中存在的自定义类"属性"的混合来调用自定义操作。
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。