Unity实现一个简单易用的对象池

Unity实现简单易用的对象池

原理

当场景中需要频繁实例化一种对象时,由于实例化的过程会比较耗时,所以可以事先创建一堆对象,然后在需要时激活它。
池子中,我们有两个列表,一个是正在被使用的对象,另一个是还没有被使用的对象,需要一个物体时,从正在使用的列表中取出一个物体,然后将它标记为“已被使用”,其实就是放到“已被使用的”列表中。当物体被使用完,归还物体到池中时,进行相反的操作。
##源码

public static class ObjectPool
{
    
    
    private class ObjectBuffer<T> where T : MonoBehaviour
    {
    
    
        public T prefab = null;
        public int initSize = 0;
        public Action<T> onCreate = null;
        public Action<T> onPop = null;
        public Action<T> onPush = null;

        public List<T> used = new List<T>();
        public List<T> unused = new List<T>();

        public void Grow()
        {
    
    
            T obj;
            for (int i = 0; i < initSize; ++i)
            {
    
    
                obj = GameObject.Instantiate<T>(prefab);
                onCreate?.Invoke(obj);
                unused.Add(obj);
            }
        }

        public T Pop()
        {
    
    
            if (unused.Count <= 0)
                Grow();

            T obj = unused[0];
            unused.RemoveAt(0);
            used.Add(obj);
            onPop?.Invoke(obj);
            return obj;
        }

        public void Push( T obj )
        {
    
    
            if (used.Contains(obj))
            {
    
    
                used.Remove(obj);
                unused.Add(obj);
                onPush?.Invoke(obj);
            }
        }
    }

    private static Dictionary<Type, object> m_buffers = new Dictionary<Type, object>();
    public static void CreatePool<T>( T prefab, Action<T> onCreate = null, Action<T> onPop = null, Action<T> onPush = null, int count = 64 ) where T : MonoBehaviour
    {
    
    
        ObjectBuffer<T> buffer = new ObjectBuffer<T>()
        {
    
    
            prefab = prefab,
            initSize = count,
            onCreate = onCreate,
            onPop = onPop,
            onPush = onPush
        };
        buffer.Grow();
        m_buffers.Add(typeof(T), buffer);
    }

    public static T PopObject<T>() where T : MonoBehaviour
    {
    
    
        if(m_buffers.ContainsKey(typeof(T)))
        {
    
    
            if (m_buffers[typeof(T)] is ObjectBuffer<T> buffer)
                return buffer.Pop();
        }
        return null;
    }

    public static void PushObject<T>( T obj) where T : MonoBehaviour
    {
    
    
        if(m_buffers.ContainsKey(typeof(T)))
        {
    
    
            if (m_buffers[typeof(T)] is ObjectBuffer<T> buffer)
                buffer.Push(obj);
        }
    }
}

例子:
子弹类

public class Bullet : MonoBehaviour
{
    
    
    private float life = 0;

    void Update()
    {
    
    
        life += Time.deltaTime;
        if( life > 5 )
        {
    
    
            ObjectPool.PushObject<Bullet>(this);
            life = 0;
        }
        transform.Translate(transform.forward * 0.5f);
    }
}

测试类,按下鼠标发射子弹

public class Test : MonoBehaviour
{
    
    
    [SerializeField]
    private Bullet m_prefab = null;

    private void Awake()
    {
    
    
        ObjectPool.CreatePool<Bullet>(m_prefab, OnCreateOrPush,
            x => {
    
     x.gameObject.SetActive(true); }, OnCreateOrPush);
    }

    private void OnCreateOrPush( Bullet obj)
    {
    
    
        obj.gameObject.SetActive(false);
        obj.transform.position = transform.position;
        obj.transform.rotation = transform.rotation;
    }

    private void Update()
    {
    
    
        if(Input.GetMouseButton(0))
        {
    
    
            ObjectPool.PopObject<Bullet>();
        }
    }
}

猜你喜欢

转载自blog.csdn.net/sdhexu/article/details/115399503