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);
    }
}
相关推荐
omegayy1 天前
Unity 2022.3.x部分Android设备播放视频黑屏问题
android·unity·视频播放·黑屏
Y第五个季节1 天前
Redis - HyperLogLog
数据库·redis·缓存
虾球xz1 天前
游戏引擎学习第200天
学习·游戏引擎
Justice link1 天前
企业级NoSql数据库Redis集群
数据库·redis·缓存
〆、风神1 天前
Guava Cache 实战:构建高并发场景下的字典数据缓存
缓存·guava
woshihedayu1 天前
虚幻引擎控制角色跟随移动方向旋转的方法
游戏引擎·虚幻
虾球xz1 天前
游戏引擎学习第199天
学习·游戏引擎
与火星的孩子对话1 天前
Unity3D开发AI桌面精灵/宠物系列 【三】 语音识别 ASR 技术、语音转文本多平台 - 支持科大讯飞、百度等 C# 开发
人工智能·unity·c#·游戏引擎·语音识别·宠物
向宇it1 天前
【零基础入门unity游戏开发——2D篇】2D 游戏场景地形编辑器——TileMap的使用介绍
开发语言·游戏·unity·c#·编辑器·游戏引擎
极客天成ScaleFlash1 天前
极客天成NVFile:无缓存直击存储性能天花板,重新定义AI时代并行存储新范式
人工智能·缓存