缓存池需求
1.有一个公共存储空间
2.当我们需要一个对象时从这个公共空间去获取。
若空间中有想要的对象,直接返回使用。
若空间中没有想要的对象,就去创建一个需要的对象并返回。
3.当对象使用完毕时不删除,而是放入这个公共空间待下次使用。
缓存池的作用
将频繁使用的对象放入缓存池,可以节约cup开销,但是会有内存开销。用内存换cpu性能的典型表现。一般子弹,特效等相关对象会使用缓存池。
原理
制作思路
缓存池是一个管理者角色(单例模式)
缓存池可以作为多种对象容器(Dictionary+List)
缓存池中可以取,可以放:
放入方法
取出方法
缓存池知识点
1.单例模式
2.Dictionary
3.List
4.GameObject.SetActive()
5.GameObject.Instantiate
6.Resources.load
代码
/// <summary>
/// 单例模式基类
/// </summary>
/// <typeparam name="T"></typeparam>
public class BaseManger<T> where T : new()
{
private static T _instance;
public static T instance
{
get
{
if (_instance == null)
{
_instance = new T();
}
return _instance;
}
}
}
/// <summary>
/// 缓存池模块
/// 1.Dictionary List
/// 2.Gameobject和Resources 两个公共类的API
/// </summary>
public class poolMgr:BaseManger<poolMgr>
{
//缓存池容器
public Dictionary<string, List<GameObject>> poolDic = new Dictionary<string, List<GameObject>>();
/// <summary>
/// 往外拿东西
/// name是预设体的名字和路径
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject GetObj(string name)
{
GameObject obj = null;
//缓存池里有gameobject
if (poolDic.ContainsKey(name) && poolDic[name].Count > 0)
{
obj = poolDic[name][0];
poolDic[name].RemoveAt(0);
}
//缓存池没有,加载预设体
else
{
obj = GameObject.Instantiate(Resources.Load<GameObject>(name));
//把对象名字改的和池子名字一样
obj.name = name;
}
//取出来的时候激活
obj.SetActive(true);
return obj;
}
/// <summary>
/// 还暂时不用的东西
/// </summary>
public void PushObj(string name,GameObject obj)
{
//放进去的时候让gameobject失活
obj.SetActive(false);
//里面有gameobject
if (poolDic.ContainsKey(name))
{
poolDic[name].Add(obj);
}
//里面没有
else
{
poolDic.Add(name, new List<GameObject>() { obj });
}
}
}
测试
写一个测试脚本,随便挂载空物体Gameobject上,鼠标摁下左键创建Cube,鼠标摁下右键创建Sphere。
public class PoolTest : MonoBehaviour
{
void Update()
{
if (Input.GetMouseButtonDown(0))
{
poolMgr.instance.GetObj("Test/Cube");
}
if (Input.GetMouseButtonDown(1))
{
poolMgr.instance.GetObj("Test/Sphere");
}
}
}
在Resources/Test目录下创建Cube和Sphere的预设体
写一个延迟放入缓存池的脚本,挂载到Cube和Sphere上。
public class DelayPush : MonoBehaviour
{
//当对象激活时 会进入的生命周期函数
void OnEnable()
{
Invoke("push", 1);
}
// Update is called once per frame
void push()
{
poolMgr.instance.PushObj(this.gameObject.name, this.gameObject);
}
}
缺点:暴露在Hierarchy面板下,最好能放入一个父对象层级下。