【问题标题】:Select an instance of a gameObject from a List从列表中选择一个游戏对象的实例
【发布时间】:2025-12-25 13:45:06
【问题描述】:

我想测试一个游戏对象是否是另一个游戏对象的实例,但我所拥有的似乎不起作用。我正在尝试制作一个池脚本来池项目而不是创建/销毁它们。

这是我目前正在做的事情:

// Holds all the items that can be instantiated
private List<PoolItems> poolItems = new List<PoolItems>();

// Holds all the pooled items (displayed in the hierarchy active/inactive)
private List<GameObject> gameObjects = new List<GameObject>();

// Here is how I initiate pool items:
void Start(){
    for(int i = 0; i < poolItems.Count; i++){
        GameObject obj = poolItems[i].prefab;
        for (int j = 0; j < poolItems[i].startItems; j++){
            GameObject newObj = Create(obj);
            newObj.SetActive(false);
            gameObjects.Add(newObj);
        }
    }
}

// The issue is in this method I believe:
public GameObject Instantiate(GameObject obj, Vector3 position, Quaternion rotation){
    // Find an inactive object
    GameObject foundObject = (
        from i in gameObjects
        where
            i.GetType().IsAssignableFrom(obj.GetType()) &&
            i.activeInHierarchy == false
        select i
    ).FirstOrDefault();
}

发生的情况是它只选择了列表中的第一项。

以这个层次结构为例:

Circle (Clone)
Circle (Clone)
Circle (Clone)
Square (Clone)
Square (Clone)
Square (Clone)
Square (Clone)

当我将“方形”游戏对象传递给该方法时,它仍然选择“圆形”项目。

【问题讨论】:

  • Circle 和 Square 都是 GameObject 吗?
  • 是的。它们都是预制件

标签: c# unity3d pooling


【解决方案1】:

您应该做的是将预制件分配给每个实例。

public interface IPoolItem{ GameObject Prefab { get;set; } }

将您的集合也设为该类型,而不是 GameObject。 当您创建一个新项目并将其放入池中时,您还将预制件分配给它:

void Start(){
    for(int i = 0; i < poolItems.Count; i++){
        GameObject obj = poolItems[i].prefab;
        for (int j = 0; j < poolItems[i].startItems; j++){
            GameObject newObj = Create(obj); 
            newObj.GetComponent<IPoolItem>().Prefab = obj;
            newObj.SetActive(false);
            gameObjects.Add(newObj);
        }
    }
}

分配应该在 Create 中(但我在你的问题中没有它),它还应该首先检查对象是否包含 IPoolItem 组件。然后它将引用推送到列表中。

然后,您可以遍历您的池项目集合并获得一个处于非活动状态的项目。然后你将它的 prefab 与传递给方法的 prefab 进行比较:

 public GameObject Instantiate(GameObject obj, Vector3 position, Quaternion rotation){
    foreach(IPoolItem item in poolItems){
        if(item.activeSelf == true){continue;}
        if(item.Prefab == obj) { return item.gameObject;}
    }
    return null;
}

有一些方法可以使用 Dictionary> 来优化它,这可以在您查找正方形时避免循环迭代。此外,您可以检查预制件是否已在字典中注册,这样您就不会白白进行迭代。 IPoolItem 还可以包含一个用作 OnEnable 的 Init 方法,以便在弹出项目时也对其进行初始化。

最后,如果您使用队列而不是列表,您可以在获取时出列并在重置时入队。然后你不需要迭代,因为你的队列在前面包含一个有效的项目或者是空的。

【讨论】:

最近更新 更多