[Unity3D]通用對象池類ResourcePool

通用對象池,使用時會將常用的對象至於池頂,如果設置了池的大小,超出池的未經常使用的對象將被移除,並且執行回調,可在回調中對移除對象進行其他操作。
可對壓入的對象進行命名,通過名字來進行查找和刪除。

源碼

using System.Collections;
using System.Collections.Generic;
using System;
using System.Linq;

namespace XM.Tool
{
    public class ResourcePool<T> : IEnumerable<ResourcePool<T>.ResInfo> where T : class
    {
        public class ResInfo
        {
            public string path;
            public T res;

            public ResInfo(string p, T r)
            {
                path = p;
                res = r;
            }

            public bool HasRes()
            {
                return res != null;
            }
        }

        private Action<List<ResInfo>> _onRemove;
        private int _poolMaxSize = 0;
        private List<ResInfo> _poolLst = new List<ResInfo>();
        //public List<ResInfo> Pool { get { return _poolLst; } }
        public int PoolMaxSize { get { return _poolMaxSize; } }
        public int PoolSize { get { return _poolLst.Count; } }


        public ResourcePool(Action<List<ResInfo>> onRemove = null, int maxSize = 0)
        {
            _onRemove = onRemove;
            _poolMaxSize = maxSize;
        }

        ~ResourcePool()
        {
            //
            Clear();
        }

        public void SetRemoveCallback(Action<List<ResInfo>> onRemove)
        {
            _onRemove = onRemove;
        }

        /// <summary>
        /// 設置大小
        /// </summary>
        /// <param name="maxSize">大於等於0,0 表示無限大</param>
        public void SetMaxSize(int maxSize)
        {
            _poolMaxSize = maxSize;
            CheckSize();
        }

        public List<T> GetAllRes()
        {
            return _poolLst.Select((t) => { return t.res; }).ToList();
        }

        public List<string> GetAllPath()
        {
            return _poolLst.Select((t) => { return t.path; }).ToList();
        }

        public void Push(T res, bool checkSize = true, string path = "", bool updateExsit = false)
        {
            ResInfo resInfo = new ResInfo(path, res);

            if (updateExsit)
            {
                //刪除已有的
                List<ResInfo> removeLst = _poolLst.FindAll((t) => { return string.Compare(path, t.path) == 0; });
                _poolLst.RemoveAll((t) => { return string.Compare(path, t.path) == 0; });
                OnRemove(removeLst);
            }

            _poolLst.Add(resInfo);

            if (checkSize)
            {
                CheckSize();
            }
        }

        public void Push(List<T> resLst, bool checkSize = true, string path = "", bool updateExsit = false)
        {
            foreach (var res in resLst)
            {
                Push(res, false, path, updateExsit);
            }

            if (checkSize)
            {
                CheckSize();
            }
        }

        public ResInfo Pop()
        {
            ResInfo res = null;
            if (_poolLst.Count > 0)
            {
                int index = _poolLst.Count - 1;
                res = _poolLst[index];
                _poolLst.RemoveAt(index);
            }

            return res;
        }

        public ResInfo Pop(string path)
        {
            ResInfo res = null;

            if (_poolLst.Count > 0)
            {
                int index = _poolLst.FindIndex(t => (t.path == path));
                if (index != -1)
                {
                    res = _poolLst[index];
                    _poolLst.RemoveAt(index);
                }
            }

            return res;
        }

        public T PopExt(string path = null)
        {
            var res = Pop(path);
            if (res == null)
            {
                return null;
            }

            return res.res;
        }
        public T PopExt()
        {
            var res = Pop();
            if (res == null)
            {
                return null;
            }

            return res.res;
        }

        public ResInfo LookLast()
        {
            ResInfo res = null;

            if (_poolLst.Count > 0)
            {
                res = _poolLst[0];
            }

            return res;
        }

        public ResInfo LookFirst()
        {
            ResInfo res = null;

            if (_poolLst.Count > 0)
            {
                res = _poolLst[_poolLst.Count - 1];
            }

            return res;
        }

        public T Get(string path)
        {
            int resIndex = _poolLst.FindIndex((t) => { return string.Compare(path, t.path) == 0; });
            if (resIndex == -1)
            {//未找到
                return null;
            }

            //移動到棧頂
            ResInfo res = _poolLst[resIndex];
            _poolLst.RemoveAt(resIndex);
            _poolLst.Add(res);

            return res.res;
        }

        public void Remove(T res)
        {
            List<ResInfo> removeLst = _poolLst.FindAll((t) => { return t.res == res; });
            _poolLst.RemoveAll((t) => { return t.res == res; });
            OnRemove(removeLst);
        }

        public void Remove(string path)
        {
            List<ResInfo> removeLst = _poolLst.FindAll((t) => { return t.path == path; });
            _poolLst.RemoveAll((t) => { return t.path == path; });
            OnRemove(removeLst);
        }

        public void Clear()
        {
            List<ResInfo> removeLst = new List<ResInfo>(_poolLst);
            _poolLst.Clear();
            OnRemove(removeLst);
        }

        public void CheckSize()
        {
            if (_poolMaxSize == 0)
            {
                return;
            }

            int overflowSize = _poolLst.Count - _poolMaxSize;
            if (overflowSize > 0)
            {//超出存儲範圍
             //移除棧底元素
                List<ResInfo> removeLst = _poolLst.GetRange(0, overflowSize);
                _poolLst.RemoveRange(0, overflowSize);
                OnRemove(removeLst);
            }
        }

        private void OnRemove(List<ResInfo> removeLst)
        {
            if (_onRemove != null)
            {//移除元素回調
                _onRemove(removeLst);
            }
        }

        public IEnumerator<ResInfo> GetEnumerator()
        {
            return ((IEnumerable<ResInfo>)_poolLst).GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return ((IEnumerable<ResInfo>)_poolLst).GetEnumerator();
        }
    }
}

使用方式

using System.Collections.Generic;
using UnityEngine;
using XM.Tool;

public class Test : MonoBehaviour
{
    //對象池
    ResourcePool<GameObject> _pool;

    void Start()
    {
        //初始化
        _pool = new ResourcePool<GameObject>(OnRemove, 5);
    }

    private void OnRemove(List<ResourcePool<GameObject>.ResInfo> objs)
    {
        //銷燬移除的對象
        foreach (var obj in objs)
        {
            //是否存在
            if (obj.HasRes())
            {
                //銷燬
                Destroy(obj.res);
            }
        }
    }

    public GameObject GetObj()
    {
        GameObject obj = null;

        //優先從pool中獲取
        obj = _pool.PopExt();

        if (null == obj)
        {//否則創建
            obj = new GameObject(Time.time.ToString());
        }
        else
        {//激活物體
            obj.SetActive(true);
        }

        return obj;
    }

    public void RecycleObj(GameObject obj)
    {
        //禁用物體
        obj.SetActive(false);
        //置入pool中,等待複用
        _pool.Push(obj);
    }

    //當前回收的對象名字
    string _recycleObjName = "";

    public void OnGUI()
    {
        //創建對象
        if (GUILayout.Button("Create Obj"))
        {
            GetObj();
        }

        //回收對象
        _recycleObjName = GUILayout.TextField(_recycleObjName);
        if (GUILayout.Button("Recycle Obj"))
        {
            GameObject obj = GameObject.Find(_recycleObjName);
            if (null != obj)
            {
                RecycleObj(obj);
            }
        }

        //清理對象池
        if (GUILayout.Button("Clear Pool"))
        {
            _pool.Clear();
        }
    }
}

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章