简体   繁体   English

从列表中选择一个gameObject的实例

[英]Select an instance of a gameObject from a List

I would like to test and see if a gameobject is an instance of another gameobject, but what I have doesn't seem to be working. 我想测试一个游戏对象是否是另一个游戏对象的实例,但是我所拥有的似乎不起作用。 I am trying to make a pooling script to pool items instead of creating/destroying them. 我正在尝试创建一个池脚本来池项目,而不是创建/销毁它们。

Here is what I am currently doing: 这是我目前正在做的事情:

// 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();
}

What is happening is that it just selects the first item in the list. 发生的事情是它只选择了列表中的第一项。

Take this hierarchy for example: 以这个层次结构为例:

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

When I pass a "Square" gameObject to the method, it still selects a "Circle" item. 当我将“ Square”游戏对象传递给方法时,它仍然选择“ Circle”项。

What you should be doing is to assign the prefab to each instance. 您应该做的是将预制件分配给每个实例。

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

Make your collection of that type as well instead of GameObject. 也使该类型的集合成为GameObject的集合。 When you create a new item and place it in the pool, you also assign the prefab to it: 当您创建新项目并将其放置在池中时,您还为它分配了预制件:

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);
        }
    }
}

The assignment should be in Create (but I don't have it in your question) and it should also check first that the object contains a IPoolItem component. 分配应在“创建”中(但您的问题中没有),它还应首先检查对象是否包含IPoolItem组件。 Then it pushes the reference in the list. 然后,它将引用推入列表中。

Then you can iterate through your collection of pooled item and get one that is inactive. 然后,您可以遍历集合的项的集合,并获得未激活的项。 Then you compare its prefab to the prefab passed to the method: 然后,将其预制件与传递给该方法的预制件进行比较:

 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;
}

There are ways to optimise it all with a Dictionary> which would spare the iteration of circles when you look for squares. 有多种方法可以使用Dictionary>对其进行优化,当您寻找正方形时,该方法可以避免圆的重复。 Also, you could check if the prefab is registered in the dictionary so that you don't iterate for nothing. 另外,您可以检查预制件是否已在字典中注册,以便您无需进行任何迭代。 The IPoolItem could also contain a Init method that would act as a OnEnable so that when you pop an item you also initialize it. IPoolItem也可以包含一个Init方法,该方法用作OnEnable,以便在弹出项目时也可以对其进行初始化。

Finally, if you'd use a Queue instead of a List you could Dequeue when getting and Enqueue when resetting. 最后,如果您使用队列而不是列表,则可以在获取时出队,在重置时入队。 Then you don't need to iterate since your queue contains a valid item on the front or is empty. 然后,您不需要进行迭代,因为您的队列的前面包含一个有效项目或为空。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM