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);
    }
}
相关推荐
新手unity自用笔记7 小时前
unity网络基础_1
网络·unity·游戏引擎
番茄炒鸡蛋加糖9 小时前
缓存三大问题
缓存
江晓鱼未暖14 小时前
十七、Redis 核心原理与架构详解
大数据·数据库·数据仓库·redis·缓存·架构
小罗水14 小时前
第13章 Redis 缓存、幂等锁与任务状态
数据库·redis·缓存
热心市民lcj14 小时前
Spring Boot 整合 Caffeine 本地缓存实战
spring boot·后端·缓存
zx11545016 小时前
【热点 Key 探测与加长缓存 TTL 实战】
缓存
谢斯16 小时前
[vscode] 使用unity打开vscode的取消.csproj的显示
ide·vscode·unity
魔术师Dix17 小时前
StartGame:Unity TDD 外部工程指南
学习·游戏·unity·c#·测试驱动开发
toooooop81 天前
如何用 ss + ps 精准定位本机 Redis 的“隐形”消费者?
linux·数据库·redis·缓存
软萌萌的11 天前
C#中的多级缓存架构设计与实现深度解析
缓存·c#·wpf