首先我们来谈一谈对象池技术的介绍:由于Cpu回收游戏对象和创建游戏对象,涉及到内存的分配和回收,研究过操作的同学应该知道当应用程序也就是我们的游戏需要生产一个怪物的时候,我们首先会和操作系统申请一份内存区域准备存放我们的游戏怪物,这个时候操作系统会去检测有没有容的下我们怪物内存大小啊,这个操作就是细活,cpu这个时候会进行许多的工作,当我们怪物掉血死忙的时候我们需要把怪物从屏幕中清除出去,如果我们直接Destory(销毁对象,0f)掉,我们的操作系统会去查找各种表,这个表是记录那些内存被使用,如果回收了会被标志为空闲,并且如果当前回收的内存附近也是有空间内存,还会进行内存合并。这个是非常吃cpu的,尽管unity会进行优化等cpu空闲的在去合并空闲内存。
基于上述CPU的销毁,我们引进对象池技术,我们可以预先生产10个怪物,然后禁用也就是让他在内存中,但是不参与和CPU的交互。当我们游戏回合开始的时候我们需要出怪的时候我们不是直接去实例化对应的数量,而是通过对象池去取出对象需要的怪物数量,当怪物死忙的时候我们不是去销毁而是告诉对象池你来回收他。有一点,我们的对象池会传递到出怪的全部场景。很明显我们看到的情况是用内存换CPU的运作。这个时候我们的池子里预先生产的怪物数量比例特别重要,一要考虑内存不能暂用过多,二是不能出现预先的准备不足还要经常实例化那对象池技术没有多大效果。
对象池每个人的设计要根据实际需求,比如你的游戏在很长一段时间并没有怪物的产出,这个时候你可以清理一些空闲出内存后续使用。
如果我们对象池想管理不同的对象,比如怪物,音乐资源,等,我们可以根据他进行池子分类,有怪物子池子和音乐子池子。然后统一交给父池子管理。
理论太多头也晕,下面上主要的代码:
子池子
public class SubPool
{
Transform m_parent;
//预设
GameObject m_prefab;
//集合
List<GameObject> m_objects = new List<GameObject>();
//名字标识
public string Name
{
get { return m_prefab.name; }
}
//构造
public SubPool(Transform parent, GameObject prefab)
{
this.m_parent = parent;
this.m_prefab = prefab;
}
//取对象
public GameObject Spawn()
{
GameObject go = null;
foreach (GameObject obj in m_objects)
{
if (!obj.activeSelf)
{
go = obj;
break;
}
}
if (go == null)
{
go = GameObject.Instantiate<GameObject>(m_prefab);
go.transform.parent = m_parent;
m_objects.Add(go);
}
go.SetActive(true);
go.SendMessage("OnSpawn", SendMessageOptions.DontRequireReceiver);
return go;
}
//回收对象
public void Unspawn(GameObject go)
{
if(Contains(go))
{
go.SendMessage("OnUnspawn", SendMessageOptions.DontRequireReceiver);
go.SetActive(false);
}
}
//回收该池子的所有对象
public void UnspawnAll()
{
foreach(GameObject item in m_objects)
{
if (item.activeSelf)
{
Unspawn(item);
}
}
}
//是否包含对象
public bool Contains(GameObject go)
{
return m_objects.Contains(go);
}
}
下面逐一分析子池子代码:我们给了子池子一些关键字m_parent这个是父池子传给我的,用于子池子造的怪物需要放的位置,我们unity一般是说这里
不能让实例出来的对象在层级面板位置乱放,不方便查找和管理。
第二个字段就是怪物的预设肯定是给这个子池子的,不然子对象池在你发出Spawn()指令取怪物的时候怎么实例化呢。当然你是可以通过代码去拿到的,这里我们选择外界直接填充到这个字段里,当前子池子就可以随意的去造对象。
第三字段m_objects 保存了当前实例化出来的全部怪物实例,还有一个名字的属性,我们直接用预设名称了。由于我们对池子是根据不同对象类型进行分类,那么名字肯定是唯一的,这个时候我们可以拿这个名字和字典的对象实例去一一对应,也就是索引,不知道你们还记得那个哈希函数不。我们把通过一个名字等于是内存编号直接可以读取内存里面的数据也就是怪物。这个查找效率是非常高的。
接下来就是子池子对外有个构造函数以及需要的外界进行输入的数据定义。
下面到了重点就是生产怪物和回收怪物待续…………………..
2608

被折叠的 条评论
为什么被折叠?



