unity对象缓存技术ObjectPool

首先先看下通过ObjectPool实现的一个小的效果,效果如下

""

通过视频我们可以在Hierarchy窗口看到Sphere对象列表,出现,隐藏然后又active,然后又隐藏。

具体实现逻辑如下

step1 创建子弹预制体并绑定脚本。

子弹的预制体比较简单这里就不列举了,脚本我们呢取名字为BulletController,脚本处理如下:

csharp 复制代码
 public class BulletController : MonoBehaviour
{
    public float speed;
    public float exitTime;
    public float radiam;
    public float timer;
 
    public void ResetTime()
    {
        timer = 0f;
    }

    void Update()
    {
        timer += Time.deltaTime;
        if (timer > exitTime)
        {
            PlayerController.bulletPool.Release(gameObject);
            // Destroy(gameObject);
        }
        transform.position += new Vector3(speed * Time.deltaTime * Mathf.Sign(radiam+ timer*5),
            speed * Time.deltaTime * Mathf.Cos(radiam + timer * 5), 0);
    }
}

基本逻辑实现就是在update里面做时间累加,累加到一定时间就销毁物体,但是3D物体的创建销毁会造成UI的堵塞,因此我们这边使用对象池调用对象池的Release方法回收物体。ResetTime作用是重置物体状态。

step2 创建子弹发射器并通过对象池实现子弹的发射收集过程

csharp 复制代码
//创建对象池并添加回调  
//defaultCapacity默认开辟对象数量(unity会给我们在内存开辟空间但并不会实例化对象)
// maxSize 对象池最大容量
 ulletPool = new ObjectPool<GameObject>(CreateFunc, ActionOnGet, ActionOnRelease, ActionOnDestroy, true, 
  defaultCapacity: 10, maxSize:20);
  
 //创建物体回调 在这个回调中当对象池内容不够时会被回调
 private GameObject CreateFunc()
 {
    return  Instantiate(bulletPrefab, _MTransform.position, Quaternion.identity);
 }
 //当使用物体时调用 这里我们的处理是让物体显示
 private void ActionOnGet(GameObject @object)
 {
     @object.SetActive(true);
 }
//当物体回收的时候调用这块处理是让物体隐藏
private void ActionOnRelease(GameObject @object)
{
    @object.SetActive(false);
}
 //当要创建的物体超过对象池容量的时候
 //然后对象池需要回收掉需要的对象多余创建的对象会调用这个回调通知销毁
 private void ActionOnDestroy(GameObject @object)
 {
     Destroy( @object );
 }

通过上面的处理我们理解了对象池各个回调的作用以及调用时机,下面我们看下调用逻辑

step3 调用对象池处理

这块处理也是很简单的

csharp 复制代码
btn.onClick.AddListener(() => {
    int d = 2;
    float d_angle = 360 / d;
    float radium = 360 / d * Mathf.PI / 180;
    for (int i = 0; i < d; i++)
    {
        GameObject g = bulletPool.Get();
        BulletController bullet = g.GetComponent<BulletController>();
        bullet.transform.position = _MTransform.position;
        bullet.transform.rotation = Quaternion.identity;
        bullet.radiam = radium * i;
        bullet.ResetTime();
    }
});

这块处理也是很简单for循环创建物体,当然我们不是实例化预制体也不是new Object而是通过**bulletPool.Get()**这个方法取到对象,并给对象的脚本赋默认值。

step4总结

最后我们总结一下ObjectPool 使用

1,.首先创建对象,并完成各个回调处理

2.然后在需要获取物体的地方使用 ObjectPool.Get() 获取物体

3.然后当物体需要销毁的时候通过 ObjectPool.Release(gameObject) 回收物体(ObjectPool会根据设置的阈值判定是回收物体还是销毁物体)

最后把PlayerController的源码放在这里

csharp 复制代码
public class PlayerController : MonoBehaviour
{
    [SerializeField]
    private float speed;
    [SerializeField]
    private GameObject bulletPrefab;
    [SerializeField]
    private Button btn;

    private Transform _MTransform;
    public static ObjectPool<GameObject> bulletPool;

    void Start()
    {
        _MTransform = transform;
        bulletPool = new ObjectPool<GameObject>(CreateFunc, ActionOnGet, ActionOnRelease, ActionOnDestroy, true,
            defaultCapacity: 10, maxSize:20);
        btn.onClick.AddListener(() => {
            int d = 2;
            float d_angle = 360 / d;
            float radium = 360 / d * Mathf.PI / 180;
            for (int i = 0; i < d; i++)
            {
                /* GameObject g = Instantiate(bulletPrefab, _MTransform.position, Quaternion.identity);
                 BulletController bullet = g.GetComponent<BulletController>();*/
                GameObject g = bulletPool.Get();
                BulletController bullet = g.GetComponent<BulletController>();
                bullet.transform.position = _MTransform.position;
                bullet.transform.rotation = Quaternion.identity;
                bullet.radiam = radium * i;
                bullet.ResetTime();
            }
        });
    }

    private GameObject CreateFunc()
    {
        GameObject g = Instantiate(bulletPrefab, _MTransform.position, Quaternion.identity);
        BulletController bullet = g.GetComponent<BulletController>();
        Debug.Log("CreateFunc  " + bulletPool.CountInactive);
        return g;
    }

    private void ActionOnGet(GameObject @object)
    {
        @object.SetActive(true);
        Debug.Log("ActionOnGet  " + bulletPool.CountInactive);
    }
    private void ActionOnRelease(GameObject @object)
    {
        @object.SetActive(false);
        Debug.Log("ActionOnRelease  " + bulletPool.CountInactive);
    }

    private void ActionOnDestroy(GameObject @object)
    {
        Destroy( @object );
        Debug.Log("ActionOnDestroy  " + bulletPool.CountInactive);
    }
}
相关推荐
黄连木笛2 小时前
Redis Insight 汉化教程:Windows / macOS / Linux 设置中文界面(附繁體、教程汉化、关闭自动更新)
数据库·redis·缓存
威嵌神州15 小时前
嵌入式排故实录:高并发下串口数据“超时丢包”的根因剖析与架构优化
运维·服务器·嵌入式硬件·缓存
寂寞的船1 天前
【Unity知识速递】第13期 Unity 内存泄漏排查实战:从 Memory Profiler 到 Lua 引用泄漏的生产级全链路诊断
unity·junit·c#·游戏引擎·lua
nice_lcj5201 天前
LRU 缓存入门:它是什么、怎么用、面试怎么手写
java·数据结构·缓存·面试·lru
寂寞的船2 天前
【Unity Bug挑战】第12期 Awaitable 二次 await 死锁之谜 —— 为什么同一个异步操作等两次就卡死?
unity·c#·游戏引擎·bug
羑悻的小杀马特2 天前
Redis持久化三剑客:RDB二进制快照、AOF文本日志、混合模式如何守护你的数据安全?
数据库·redis·缓存·aof·持久化存储·rdb
时间的拾荒人2 天前
Redis 进阶实战:渐进式遍历、持久化机制与事务详解
数据库·redis·缓存
2501_933923253 天前
解读Redis:单线程模型
数据库·redis·缓存
时间的拾荒人3 天前
Redis 集合类型详解:Set 与 Zset
redis·缓存·面试