欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity 对象池

程序员文章站 2022-07-13 15:01:27
...

参考 https://blog.csdn.net/wangjiangrong/article/details/80196676

Unity 对象池
代码结构

Unity 对象池
Unity 对象池

ObjcetPool用来新建和回收游戏里的对象(prefab) 如 setActive(false)啥的
ObjcetPool.cs

public class ObjectPool
{
    private Queue<GameObject> m_PoolQueue;


    private string m_PoolName;

    protected Transform m_Parent;

    // 需要缓存的对象
    private GameObject prefab;

    // 最大容量
    private int m_MaxCount;

    protected const int m_DefaultMaxCount = 10;

    public GameObject Prefab { get => prefab; set => prefab = value; }

    public ObjectPool()
    {
        m_MaxCount = m_DefaultMaxCount;
        m_PoolQueue = new Queue<GameObject>();
    }

    public virtual void Init(string poolName, Transform transform)
    {
        m_PoolName = poolName;
        m_Parent = transform;
    }

    public virtual GameObject Get(Vector3 pos, float lifetime)
    {
        if (lifetime < 0)
        {
            return null;
        }
        GameObject returnObj;
        if (m_PoolQueue.Count > 0)
        {
            returnObj = m_PoolQueue.Dequeue();
        }
        else
        {
            // 池中没有可分配对象了,新生成一个
            returnObj = GameObject.Instantiate<GameObject>(prefab);
            returnObj.transform.SetParent(m_Parent);
            returnObj.SetActive(false);
        }
        // 使用PrefabInfo脚本保存returnObj的一些信息
        ObjectInfo info = returnObj.GetComponent<ObjectInfo>();
        if (info == null)
        {
            info = returnObj.AddComponent<ObjectInfo>();
        }

        info.PoolName = m_PoolName;
        if (lifetime > 0)
        {
            info.Lifetime = lifetime;
        }

        returnObj.transform.position = pos;
        returnObj.SetActive(true);

        return returnObj;
    }

    // "销毁对象" 其实是回收对象
    public virtual void Remove(GameObject obj)
    {
        if (m_PoolQueue.Contains(obj))
        {
            return;
        }

        if (m_PoolQueue.Count > m_MaxCount)
        {
            // 对象池已满 直接销毁
            GameObject.Destroy(obj);
        }
        else
        {
            // 放入对象池
            m_PoolQueue.Enqueue(obj);
            obj.SetActive(false);
        }
    }

    public virtual void Destroy()
    {
        m_PoolQueue.Clear();
    }


}

CubePool 用来对游戏里的对象进行特殊处理 (这里是改变颜色)

CubePool.cs

public class CubePool : ObjectPool
{
    public override GameObject Get(Vector3 pos, float lifetime)
    {
        GameObject obj;
        obj  =  base.Get(pos, lifetime);

        obj.GetComponent<Renderer>().material.color = Random.ColorHSV();

        return obj;
    }
}

ObjcetPoolManager 用来管理多个对象池
ObjcetPoolManager.cs

public class ObjectPoolManager : Singleton<ObjectPoolManager>
{
    private Dictionary<string, ObjectPool> m_PoolDic;

    private Transform m_RootPoolTrans;

    public ObjectPoolManager()
    {
        m_PoolDic = new Dictionary<string, ObjectPool>();

        // 根对象池
        GameObject go = new GameObject("ObjcetPoolManager");
        m_RootPoolTrans = go.transform;
    }

    // 创建一个新的对象池
    public T CreateObjectPool<T>(string poolName) where T : ObjectPool, new()
    {
        if (m_PoolDic.ContainsKey(poolName))
        {
            return m_PoolDic[poolName] as T;
        }

        GameObject obj = new GameObject(poolName);
        obj.transform.SetParent(m_RootPoolTrans);
        T pool = new T();
        pool.Init(poolName, obj.transform);
        m_PoolDic.Add(poolName, pool);
        return pool;
    }

    public GameObject GetGameObject(string poolName, Vector3 position, float lifetTime)
    {
        if (m_PoolDic.ContainsKey(poolName))
        {
            return m_PoolDic[poolName].Get(position, lifetTime);
        }
        return null;
    }

    public void RemoveGameObject(string poolName, GameObject go)
    {
        if (m_PoolDic.ContainsKey(poolName))
        {
            m_PoolDic[poolName].Remove(go);
        }
    }
    
    // 销毁所有对象池
    public void Destroy()
    {
        m_PoolDic.Clear();
        GameObject.Destroy(m_RootPoolTrans);

    }
}

MoveUp.cs 就一个向上运动的脚本

void Update()
 {
     transform.position += Vector3.up * Time.deltaTime * 2;
 }

ObjcetInfo.cs 用来记录对象信息 并且 定时回收对象(可根据需要自己看着办修改)

public class ObjectInfo : MonoBehaviour
{
    public float Lifetime = 0;
    public string PoolName;

    private WaitForSeconds m_WaitTime;

    private void Awake()
    {
        if (Lifetime > 0)
        {
            m_WaitTime = new WaitForSeconds(Lifetime);
        }
    }

    private void OnEnable()
    {
        if (Lifetime > 0)
        {
            StartCoroutine(CountDown(Lifetime));
        }
    }

    IEnumerator CountDown(float lifetime)
    {
        yield return m_WaitTime;
        ObjectPoolManager.Instance.RemoveGameObject(PoolName, gameObject);
    }
}

测试主程序

public class PoolDemo : MonoBehaviour
{
    private ObjectPool m_TestPool;
    public GameObject Prefab;

    public Button TestButton;

    // Start is called before the first frame update
    void Start()
    {
        m_TestPool = ObjectPoolManager.Instance.CreateObjectPool<CubePool>("CubePool");
        m_TestPool.Prefab = Prefab;


        TestButton.onClick.AddListener( () => {

            ObjectPoolManager.Instance.GetGameObject("CubePool", new Vector3(0, 0, 0), 2);
        });
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}