Unity-缓存池模块(可以跑通)

本文详细介绍了Unity中缓存池的概念和实现,通过使用PoolData类和Singleton模式来管理对象的复用,减少游戏运行时的内存开销和提高性能。缓存池以字典形式存储,按对象类别分类,支持对象的获取和回收,并提供清空缓存池的功能,适用于子弹、特效等资源的高效管理。
摘要由CSDN通过智能技术生成

理解

缓存池实际上是一个存放循环重复使用的容器。
例子:场景中的子弹,弹痕等

  • 缓存池(好比一个橱子)
    • 池子1(好比是一个橱子中的某一个抽屉)

      • 池子1中的对象们
    • 池子2(好比是一个厨子中的某一个抽屉)

      • 池子2中的对象们

      图示:在这里插入图片描述
      1.缓存池中没有,则创建
      2.缓存池中存在,则取
      3.加载采用Resources.load(name)根据名字加载,所以创建新对象时的名字,就是再次重用所取的名字,后续参数名字的一致保证了缓存池的实现。


缓存池中的抽屉类
  缓存池中有多个抽屉对应不同的预制体对象类别,预制体分类存储。

public class PoolData {

    public GameObject parentObj;      //抽屉标识(用来分类对象)
    public List<GameObject> poolList;  //对象列表

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="obj">挂载的父对象</param>
    /// <param name="poolObj">对象池根节点</param>
    public PoolData(GameObject obj,GameObject poolObj)
    {
        parentObj = new GameObject(obj.name);  //抽屉的名字
        parentObj.transform.parent = poolObj.transform;
        poolList = new List<GameObject>();
    }

    //往具体池子里放
    public void Push(GameObject obj)
    {
        poolList.Add(obj);
        obj.transform.parent = parentObj.transform;
        obj.SetActive(false);
    }

    //往池子中取对象
    public GameObject GetObj()
    {
        GameObject obj = null;
        obj = poolList[0];
        poolList.RemoveAt(0);
        obj.SetActive(true);
        obj.transform.parent = null;
        return obj;
    }
}

单例模板

public abstract class Singleton<T> : MonoBehaviour where T:MonoBehaviour
{
    private static T instance;
    public static T Instance {
        get {
            return instance;
        }
    }

    protected virtual void Awake()
    {
        if (instance == null)
        {
            instance = this as T;
        }
    }
}

缓存池管理

public class PoolMgr : Singleton<PoolMgr>
{
    protected override void Awake()
    {
        base.Awake();
    }

    //缓存池(缓存池下面是抽屉)
    public Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();
    //缓存池的父对象
    private GameObject poolObj;

    /// <summary>
    /// 从池子中的抽屉中取
    /// </summary>
    /// <param name="name">抽屉的名字</param>
    /// <returns></returns>
    public GameObject GetObj(string name)
    {
        GameObject obj = null;
        //存在这个抽屉且抽屉里面有东西
        if (poolDic.ContainsKey(name)&&poolDic[name].poolList.Count>0)  
        {
            obj = poolDic[name].GetObj();
        }
        else  //动态加载生成
        {
            obj = GameObject.Instantiate(Resources.Load<GameObject>(name));
            //要和抽屉的名字一样
            obj.name = name;
        }
        obj.SetActive(true);
        obj.transform.parent = null;
        return obj;
    }

    /// <summary>
    /// 放入池子中的对应抽屉里
    /// </summary>
    /// <param name="name">抽屉名字</param>
    /// <param name="obj">放入的物体</param>
    public void Push(string name,GameObject obj)
    {
        if (poolObj == null)
            poolObj = new GameObject("poolObj");

        if (!poolDic.ContainsKey(name))
        {
            poolDic.Add(name, new PoolData(obj,poolObj));
        }
        poolDic[name].Push(obj);
    }


完整例子
  说明这里将每个【抽屉】的名字与具体对象的名字同名,这里的作用是往缓存池中放对象时,直接能根据对象的名字在poolDic字典中找到对应的抽屉,如果有就放入,如果没有就新建一个抽屉。

using System.Collections.Generic;
using UnityEngine;

//缓存池中的抽屉
public class PoolData
{
    public GameObject parentObj;      //抽屉标识(用来分类对象)
    public List<GameObject> poolList;  //对象列表

    /// <summary>
    /// 构造函数
    /// </summary>
    /// <param name="obj">挂载的父对象</param>
    /// <param name="poolObj">对象池根节点</param>
    public PoolData(GameObject obj, GameObject poolObj)
    {
        parentObj = new GameObject(obj.name);  //抽屉的名字
        parentObj.transform.parent = poolObj.transform;
        poolList = new List<GameObject>();
    }

    //往具体池子里放
    public void Push(GameObject obj)
    {
        poolList.Add(obj);
        obj.transform.parent = parentObj.transform;
        obj.SetActive(false);
    }

    //往池子中取对象
    public GameObject GetObj()
    {
        GameObject obj = null;
        obj = poolList[0];
        poolList.RemoveAt(0);
        obj.SetActive(true);
        obj.transform.parent = null;
        return obj;
    }
}

/// <summary>
/// 缓存池管理
/// </summary>
public class PoolMgr : Singleton<PoolMgr>
{
    protected override void Awake()
    {
        base.Awake();
    }

    //缓存池(缓存池下面是抽屉)
    public Dictionary<string, PoolData> poolDic = new Dictionary<string, PoolData>();

    //缓存池的父对象
    private GameObject poolObj;

    /// <summary>
    /// 从池子中的抽屉中取
    /// </summary>
    /// <param name="name">抽屉的名字</param>
    /// <returns></returns>
    public GameObject GetObj(string name)
    {
        GameObject obj = null;
        //存在这个抽屉且抽屉里面有东西
        if (poolDic.ContainsKey(name) && poolDic[name].poolList.Count > 0)
        {
            obj = poolDic[name].GetObj();
        }
        else  //动态加载生成
        {
            obj = GameObject.Instantiate(Resources.Load<GameObject>(name));
            //要和抽屉的名字一样
            obj.name = name;
        }
        obj.SetActive(true);
        obj.transform.parent = null;
        return obj;
    }

    /// <summary>
    /// 放入池子中的对应抽屉里
    /// </summary>
    /// <param name="name">抽屉名字</param>
    /// <param name="obj">放入的物体</param>
    public void Push(string name, GameObject obj)
    {
        if (poolObj == null)
            poolObj = new GameObject("poolObj");

        if (!poolDic.ContainsKey(name))
        {
            poolDic.Add(name, new PoolData(obj, poolObj));
        }
        poolDic[name].Push(obj);
    }

    //清空缓存池
    //切换场景的时候可能为null
    public void Clear()
    {
        poolDic.Clear();
        poolObj = null;
    }
}

测试脚本

public class Test : BasePanel
{
   
    private GameObject obj;

    public Button GetBtn1;
    public Button GetBtn2;
    public Button PushBtn;
    private void Start()
    {
        //往池子中取 1
        GetBtn1.onClick.AddListener(() =>
        {
            obj = PoolMgr.Instance.GetObj("cube");
        });

        //往池子中放2
        GetBtn2.onClick.AddListener(() =>
        {
            PoolMgr.Instance.GetObj("Sphere");
        });

        //往池子中放
        PushBtn.onClick.AddListener(() =>
        {
            PoolMgr.Instance.Push("cube", obj);
        });
    }
}

将Test脚本挂载场景物体中,自己创建三个按钮,我这里用的Cube和Sphere做的测试,建一个Resources文件夹,将这两个物体拖进去制成预制体用于首次的动态加载。
在这里插入图片描述
缓存池这个小例子就可以测试了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值