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);
    }
}
相关推荐
心疼你的一切22 分钟前
Unity异步编程神器:Unitask库深度解析(功能+实战案例+API全指南)
深度学习·unity·c#·游戏引擎·unitask
啦啦啦_999941 分钟前
Redis-0-业务逻辑
数据库·redis·缓存
自不量力的A同学1 小时前
Redisson 4.2.0 发布,官方推荐的 Redis 客户端
数据库·redis·缓存
fengxin_rou1 小时前
[Redis从零到精通|第四篇]:缓存穿透、雪崩、击穿
java·redis·缓存·mybatis·idea·多线程
fengxin_rou2 小时前
黑马点评实战篇|第二篇:商户查询缓存
缓存
笨蛋不要掉眼泪2 小时前
Redis哨兵机制全解析:原理、配置与实战故障转移演示
java·数据库·redis·缓存·bootstrap
呆呆敲代码的小Y2 小时前
【Unity 实用工具篇】 | Book Page Curl 快速实现翻书效果
游戏·unity·游戏引擎·u3d·免费游戏·翻书插件
ALex_zry15 小时前
Redis Cluster 分布式缓存架构设计与实践
redis·分布式·缓存
AC梦15 小时前
unity中如何将UI上的字高清显示
ui·unity
shuair19 小时前
redis缓存预热、缓存击穿、缓存穿透、缓存雪崩
redis·spring·缓存