C# 如何调整我的对象池以重置我加载的每个新场景?

C# 如何调整我的对象池以重置我加载的每个新场景?,c#,unity3d,object-pooling,scene-manager,C#,Unity3d,Object Pooling,Scene Manager,根据答案中给出的规格更新游戏后,我现在收到以下错误消息: Assets\ObjectPooler.cs(79,41):错误CS0103:名称“pool”在当前上下文中不存在。我理解为什么它不起作用,因为它是在另一个方法中声明的,但是我如何更改代码来访问这个变量呢 提前谢谢 我还没有将发行版和.sceneloaded脚本添加到游戏中 这是我的ObjectPooler脚本: using System.Collections; using System.Collections.Generic; usi

根据答案中给出的规格更新游戏后,我现在收到以下错误消息:

Assets\ObjectPooler.cs(79,41):错误CS0103:名称“pool”在当前上下文中不存在。我理解为什么它不起作用,因为它是在另一个方法中声明的,但是我如何更改代码来访问这个变量呢

提前谢谢

我还没有将发行版和.sceneloaded脚本添加到游戏中

这是我的ObjectPooler脚本:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ObjectPooler : MonoBehaviour
{
    [System.Serializable]
    public class Pool
    {
        public string tag;
        public GameObject prefab;
        public int size;

    }

    #region Singleton 

    public static ObjectPooler Instance;

    private void Awake()
    {
        // Already another instance?
        if (Instance)
        {
            Destroy(this.gameObject);
            return;
        }

        Instance = this;
        DontDestroyOnLoad(this.gameObject);
    }

    #endregion

    public List<Pool> pools;
    public Dictionary<string, Queue<GameObject>> poolDictionary;


    // Start is called before the first frame update
    //change this method to make it work everytime level is loaded
    private Dictionary<string, Pool> prefabPools;

    private void Start()
    {
        foreach (var pool in pools)
        {
            Queue<GameObject> objectPool = new Queue<GameObject>();

            for (int i = 0; i < pool.size; i++)
            {
                GameObject obj = Instantiate(pool.prefab);
                obj.transform.SetParent(transform);
                obj.SetActive(false);
                objectPool.Enqueue(obj);
            }

            prefabPools.Add(pool.tag, pool);
            poolDictionary.Add(pool.tag, objectPool);
        }
    }

    public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation)
    {
        if (!poolDictionary.ContainsKey(tag))
        {
            Debug.LogWarning("Pool with tag" + tag + " doesn't exist.");
            return null;
        }

        GameObject objectToSpawn;

        // check if there are objects left otherwise insteantiate a new one
        if (poolDictionary[tag].Count > 0)
        {
            objectToSpawn = poolDictionary[tag].Dequeue();
        }
        else
        {
            objectToSpawn = Instantiate(pool.prefab);
            objectToSpawn.transform.SetParent(transform);
        }

        objectToSpawn.transform.position = position;
        objectToSpawn.transform.rotation = rotation;

        objectToSpawn.SetActive(true);

        IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();

        if (pooledObj != null)
        {
            pooledObj.OnObjectSpawn();
        }

        return objectToSpawn;
    }


}
以下是从脚本调用池中游戏对象的方式:

objectPooler.SpawnFromPool("Ball", spawnPoints[randomSpawnPoint].position, Quaternion.identity);
它的工作方式是,当我在游戏的不同场景之间切换对象池时,对象池的一个新实例会被创建或重置,它们会出现在屏幕上,并根据脚本进行操作,而不是像被破坏一样出现和操作。需要注意的是,如果其中一个objectpooler和对象在第一个场景中表现正常,并且仅在游戏在场景之间转换时开始抛出错误消息,那么当我编辑脚本以实例化对象而不使用objectpooler时,如中所示:

Instantiate(interact[Interact], spawnPoints[randomSpawnPoint].position,
                      Quaternion.identity); 

在我将游戏对象预置存储在一个名为interaction的公共数组中并通过索引调用它们的地方,脚本似乎也能工作。然而,为了防止代码变得昂贵,我需要能够使用ObjectPooler

首先,我不会将刚刚生成的对象重新排队,而是将其从队列中移除。然后,当队列为空时,生成新的附加对象以供使用,而不是重用可能已经存在的对象

private Dictionary<string, Pool> prefabPools;

private void Start()
{
    foreach (var pool in pools)
    {
        Queue<GameObject> objectPool = new Queue<GameObject>();

        for (int i = 0; i < pool.size; i++)
        {
            GameObject obj = Instantiate(pool.prefab);
            obj.SetActive(false);
            objectPool.Enqueue(obj);
        }

        prefabPools.Add(pool.tag, pool);
        poolDictionary.Add(pool.tag, objectPool);
    }
}

public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation)
{
    if (!poolDictionary.ContainsKey(tag))
    {
        Debug.LogWarning("Pool with tag" + tag + " doesn't exist.");
        return null;
    }

    GameObject objectToSpawn;

    // check if there are objects left otherwise insteantiate a new one
    if(poolDictionary[tag].Count > 0)
    {
        objectToSpawn = poolDictionary[tag].Dequeue();
    }
    else
    {
        objectToSpawn = Instantiate(pool.prefab);
    }

    objectToSpawn.transform.position = position;
    objectToSpawn.transform.rotation = rotation;

    objectToSpawn.SetActive(true);

    IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();

    if (pooledObj != null)
    {
        pooledObj.OnObjectSpawn();
    }

    return objectToSpawn;
}
然后确保您的池对象也不会因为使其成为此对象的子对象而被破坏

GameObject obj = Instantiate(pool.prefab);
obj.SetParent(transform);
而且在

objectToSpawn = Instantiate(pool.prefab);
objectToSpawn.SetParent(transform);
你应该有某种
Release
方法来禁用和重新排队对象,而不是像这样破坏它们

public void Release(GameObject obj)
{
    obj.SetActive(false);

    // Assuming pool.tag euqals obj.tag
    // In general I would rather go by type instead
    poolDictionary[obj.tag].Enqueue(obj);
}
最后,当场景发生变化时,对每个对象运行此操作

private void Awake()
{
    ...

    SceneManager.sceneLoaded -= OnSceneLoaded;
    SceneManager.sceneLoaded += OnSceneLoaded;
}

private void OnDestroy()
{
    ...

    SceneManager.sceneLoaded -= OnSceneLoaded;
}

private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
    foreach(var child in transform)
    {
        if(!child.activeInHierachy) continue;

        Release(child);
    }
}

或者,如果您不想让它们始终是池对象的子对象,您也可以在列表中跟踪它们,如

private List<GameObject> currentlySpawnedObjects = new List<GameObject>();

//...

public void Release(GameObject obj)
{
    currentlySpawnedObjects.Remove(obj);

    obj.SetActive(false);

    // here you should still make it a child so it doesn't get destroyed
    // when the scene is changed
    obj.SetParent(transform);

    // Assuming pool.tag euqals obj.tag
    // In general I would rather go by type instead
    poolDictionary[obj.tag].Enqueue(obj);
}

//...

// call this BEFORE switching scenes
public void ReleaseAll()
{
    foreach(var child in currentlySpawnedObjects)
    {
        Release(child);
    }
}

谢谢你的评论。只是个问题。我应该把释放方法放在哪里?我在对象池器本身中设置了一个名称,如果是,我应该将其放置在对象池器中的什么位置?如果将其放入脚本中,我应该替换什么内容呢?所有显示的方法都是
对象池器的一部分
所以是;)你可能不需要更换任何东西。。我只是说,如果场景中不再需要该对象,您将调用
Release
,而不是
Destroy
。在场景被改变之前释放所有对象是必需的,但一般来说,我不想破坏任何游戏对象,因为我不想让它们出现。我将它们设置为非活动状态。由于场景在统一中的工作方式,当场景被移除时,它们通常在场景转换之间被破坏。这是否会改变您的解决方案?是的。。这正是我为..添加的
Release
方法。。我也不销毁对象,而是将其设置为非活动+1。使它们再次可用于产卵和2。使它们成为
ObjectPooler
的子对象,以便它们继承其
DontDestroyOnLoad
属性,直到它们再次生成(因此可能会移动到另一个父对象)。好的,我将尝试实现解决方案并返回给您。谢谢你,伙计
private void Awake()
{
    ...

    SceneManager.sceneLoaded -= OnSceneLoaded;
    SceneManager.sceneLoaded += OnSceneLoaded;
}

private void OnDestroy()
{
    ...

    SceneManager.sceneLoaded -= OnSceneLoaded;
}

private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
{
    foreach(var child in transform)
    {
        if(!child.activeInHierachy) continue;

        Release(child);
    }
}
private List<GameObject> currentlySpawnedObjects = new List<GameObject>();

//...

public void Release(GameObject obj)
{
    currentlySpawnedObjects.Remove(obj);

    obj.SetActive(false);

    // here you should still make it a child so it doesn't get destroyed
    // when the scene is changed
    obj.SetParent(transform);

    // Assuming pool.tag euqals obj.tag
    // In general I would rather go by type instead
    poolDictionary[obj.tag].Enqueue(obj);
}

//...

// call this BEFORE switching scenes
public void ReleaseAll()
{
    foreach(var child in currentlySpawnedObjects)
    {
        Release(child);
    }
}
private Dictionary<string, Pool> prefabPools;

private void Start()
{
    foreach (var pool in pools)
    {
        Queue<GameObject> objectPool = new Queue<GameObject>();

        for (int i = 0; i < pool.size; i++)
        {
            GameObject obj = Instantiate(pool.prefab);
            obj.SetActive(false);
            objectPool.Enqueue(obj);
        }

        prefabPools.Add(pool.tag, pool);
        poolDictionary.Add(pool.tag, objectPool);
    }
}

public GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation, Transform parent = null)
{
    if (!poolDictionary.ContainsKey(tag))
    {
        Debug.LogWarning("Pool with tag" + tag + " doesn't exist.");
        return null;
    }

    GameObject objectToSpawn;

    // check if there are objects left otherwise insteantiate a new one
    if(poolDictionary[tag].Count > 0)
    {
        objectToSpawn = poolDictionary[tag].Dequeue();
    }
    else
    {
        objectToSpawn = Instantiate(prefabPools[tag].prefab);
    }

    if(parent)
    {
        objectToSpawn.SetParent(parent, false);
    }

    // you could also decide to use localPosition in case parent is set
    objectToSpawn.transform.position = position;
    objectToSpawn.transform.rotation = rotation;

    objectToSpawn.SetActive(true);

    IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();

    if (pooledObj != null)
    {
        pooledObj.OnObjectSpawn();
    }

    currentlySpawnedObjects.Add(objectToSpawn);

    return objectToSpawn;
}