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);
    }
}
相关推荐
酷ku的森8 小时前
Redis的缓存更新策略
缓存
野犬寒鸦10 小时前
从零起步学习Redis || 第十一章:主从切换时的哨兵机制如何实现及项目实战
java·服务器·数据库·redis·后端·缓存
zhangzhangkeji13 小时前
cesium126,230217,Pixel Streaming in Unreal Engine 像素流 - 1 基本概念:
游戏引擎·虚幻
callJJ13 小时前
缓存雪崩、击穿、穿透是什么与解决方案
缓存
如竟没有火炬15 小时前
LRU缓存——双向链表+哈希表
数据结构·python·算法·leetcode·链表·缓存
阿湯哥15 小时前
Redis数据库隔离业务缓存对查询性能的影响分析
数据库·redis·缓存
麦兜*15 小时前
Redis 7.2 新特性实战:Client-Side Caching(客户端缓存)如何大幅降低延迟?
数据库·spring boot·redis·spring·spring cloud·缓存·tomcat
he___H17 小时前
尚庭公寓中Redis的使用
数据库·redis·缓存·尚庭公寓
不良人天码星1 天前
redis-zset数据类型的常见指令(sorted set)
数据库·redis·缓存
AA陈超1 天前
虚幻引擎UE5专用服务器游戏开发-33 在上半身播放组合蒙太奇
c++·游戏·ue5·游戏引擎·虚幻