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

本文介绍了Unity中实现对象池的原理和源码,通过预先创建并管理对象,减少频繁实例化带来的性能消耗。对象池包含正在使用和未使用对象的列表,通过Pop和Push操作实现对象的复用,适用于处理如子弹等短生命周期的游戏对象。示例展示了如何创建子弹对象池,并在子弹超出寿命后自动归还到池中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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>();
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

示申○言舌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值