分享一个看到的有意思的对象池(灵活对象池)

分享一个看到的有意思的对象池(灵活对象池)

相比于传统的对象池中的对象是拿到对象之后在另外的脚本中书写逻辑,能不能给对象池中的对象都创建一个基类,创建回收或者销毁都在该池子中实现呢,并且一般的对象池不能去使用Unity常规API进行销毁其中的对象只有回收和释放,能不能有一种更自由的方式呢,根据不同的项目进行取舍即可没有最优只有最适合的方式。

1.ObjectPool

这个是对象池的总管理,里面记录着子对象池,有着创建和回收的功能

public class ObjectPool
{
    private static ObjectPool _instance;
    public static ObjectPool Instance
    {
        get { return _instance ?? (_instance = new ObjectPool()); }
    }
    
    private Dictionary<string, SubPool> poolDict = new Dictionary<string, SubPool>();

    public GameObject Create(GameObject prefab, string path)
    {
        if (!poolDict.ContainsKey(path))
        {
            SubPool subPool = new SubPool(prefab,path);
            poolDict.Add(path,subPool);
        }

        return poolDict[path].Create();
    }
    
    public void Recycle(GameObject obj)
    {
        if (obj.GetComponent<RecoverableObject>() == null)
        {
            Debug.LogError("回收失败,物体" + obj.name + "需要挂载 RecoverableObject 脚本");
        }
        obj.GetComponent<RecoverableObject>().OnRecycle();
        obj.SetActive(false);
    }
    
    public void Clear() {

        foreach (KeyValuePair<string,SubPool> pool in poolDict)
        {
            pool.Value.ClearAll();
        }
    } 
    
    internal void Remove(RecoverableObject recoverableObject)
    {
        SubPool subPool = poolDict[recoverableObject.poolID];
        subPool.Remove(recoverableObject);
    }
}

2.SubPool

子对象池,里面记录着某个预制体的对象池集合

public class SubPool
{
    private List<GameObject> m_ObjectList = new List<GameObject>();
    private GameObject m_Prefab;
    private string poolID;

    public SubPool(GameObject prefab,string poolID)
    {
        m_Prefab = prefab;
        this.poolID = poolID;
    }

    public GameObject Create()
    {
        GameObject target = null;
        foreach (GameObject go in m_ObjectList)
        {
            if (!go.activeInHierarchy)
            {
                target = go;
                break;
            }
        }

        if (target == null)
        {
            target = GameObject.Instantiate(m_Prefab);
            m_ObjectList.Add(target);
        }

        if (target.GetComponent<RecoverableObject>() == null)
        {
            Debug.LogError("生成失败,物体" + m_Prefab.name + "需要挂载 RecoverableObject 脚本");
        }

        target.GetComponent<RecoverableObject>().poolID = poolID;
        target.SetActive(true);
        target.GetComponent<RecoverableObject>().OnGenerate();
        return target;
    }

    public void RecycleAll()
    {
        foreach (GameObject obj in m_ObjectList) {
            if (!obj.activeInHierarchy) continue;
            if (obj.GetComponent<RecoverableObject>() == null)
            {
                Debug.LogError("回收失败,物体" + m_Prefab.name + "需要挂载 RecoverableObject 脚本");
            }   
            obj.GetComponent<RecoverableObject>().OnRecycle();
            obj.SetActive(false);
        }
    }
    
    public void Remove(RecoverableObject recoverableObject)
    {
        m_ObjectList.Remove(recoverableObject.gameObject);
    }
    
    public void ClearAll() {
        foreach (GameObject obj in m_ObjectList)
        {
            GameObject.Destroy(obj);
        }
        m_ObjectList.Clear();
    }
}

3.RecoverableObject

可回收的基类,所有对象池中的对象都应该挂载此类

public class RecoverableObject : MonoBehaviour
{
    public string poolID;
    
    public virtual void OnGenerate() { }

    public virtual void OnRecycle() { }

    public void OnDestroy()
    {
        ObjectPool.Instance.Remove(this);
    }
}

4.测试

public class Test : MonoBehaviour
{
    [SerializeField] private GameObject prefab;
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.K))
        {
            StartCoroutine(Delay());
        }
    }

    private IEnumerator Delay()
    {
        GameObject cube = ObjectPool.Instance.Create(prefab, "Cube");
        yield return new WaitForSeconds(2f);
        ObjectPool.Instance.Recycle(cube);
    }
}

这种对象池非常自由,我甚至可以手动用Unity的销毁对象方式销毁池中物体。

你可能感兴趣的:(Unity,unity,对象池)