对象池基本概念:
1.管理对象池的管理者
2.根据对象的名字找到对应的池子里面 的对象
概念:
- 对象池就存放需要被反复调用资源的一个空间,当一个对象回大量生成的时候如果每次都销毁创建会很费时间,通过对象池把暂时不用的对象放到一个池中(也就是一个集合),当下次要重新生成这个对象的时候先去池中查找一下是否有可用的对象,如果有的话就直接拿出来使用,不需要再创建,如果池中没有可用的对象,才需要重新创建 - 利用空间换时间来达到游戏的高速运行效果,
3. 在FPS游戏中要常被大量复制的对象包括子弹,敌人,粒子等
对象池技术就是:第一次创建的时候就将对象存储在一个池子中,当需要销毁的时候不直接销毁而是隐藏,当需要时在再次使用,就不需要再次实例化一个新的对象,直接把隐藏的对象显示并拿出来用。如果对象池中已经被隐藏的物体太久没有被重新使用,应该被真正的销毁。
1. 频繁的创建和销毁一种对象
2. 需要空间大小差不多的对象
3. 可能产生内存碎片
4. 可重用,而且创建和销毁都很消耗的对象
实例: /// <summary> /// 对象池类:用于存放相同类型的对象 /// </summary> public class SubPool { //对象池里面存放场景中所需要的游戏对象 List<GameObject> pool = new List<GameObject> (); //要创建的游戏对象的预制体 GameObject prefab; //返回预制体的名字将这个名字当做对象池的名字,在对象池管理类中, //可以通过预制体的名字找到对应的对象池 public string Name { get { return prefab.name; } } //自定义构造方法,在创建对象池对象是,就告诉当前存放的对象是哪一类型 public SubPool (GameObject obj) { prefab = obj; } //从对象池中取出游戏对象 public GameObject SubPoolSpwan () { GameObject obj = null; //遍历如果当前池子中有对象,就直接拿来用,如果没有就创建 foreach (GameObject item in pool) { //判断如果该对象处于未激活状态,该对象可用 if (item.activeSelf == false) { obj = item; break; } } //如果对象池中没有可用对象 if (obj == null) { obj = GameObject.Instantiate (prefab); //将新创建的游戏对象加入到池子中 pool.Add (obj); } //设置游戏对象激活 obj.SetActive (true); IControl control = obj.GetComponent<IControl> (); if (control != null) { control.Spawn (); } return obj; } //回收一个对象池对象 public void SubPoolUnSpwan (GameObject obj) { if (pool.Contains (obj)) { IControl control = obj.GetComponent<IControl> (); if (control != null) { control.UnSpawn (); } //设置对象未激活 obj.SetActive (false); } } //回收所有游戏对象 public void SubPoolUnSpwanAll () { //遍历所有属于激活状态的对象,进行回收 foreach (GameObject item in pool) { if (item.activeSelf) { SubPoolUnSpwan (item); } } } //检查某个游戏对象是否在对象池里 public bool SubPoolContains (GameObject obj) { return pool.Contains (obj); }
/// <summary> /// 用于管理存放各种游戏对象的对象池类 /// 管理类 /// 单例 /// </summary> public class PoolControl { private static PoolControl instance = null; private PoolControl () { } public static PoolControl Instance { get { if (instance == null) { instance = new PoolControl (); } return instance; } } //创建字典,存放各种对象池,key值为对象池名字,也即池子中对象的名字 Dictionary<string,SubPool> poolDic = new Dictionary<string, SubPool> (); //注册对象池的方法 void Register (string name) { //根据名字加载对应的预制体 GameObject obj = Resources.Load (name) as GameObject; //根据游戏对象创建对象池 SubPool subPool = new SubPool (obj); //将创建的对象池对象放到管理集合中 poolDic.Add (name, subPool); } /// <summary> /// 获取对象池中对象的方法,该方法用于提供给外部调用, /// 该方法一定会返回一个对象 /// </summary> /// <param name="name">Name.</param> public GameObject Spwan (string name) { SubPool subPool; //判断当前对象池字典中是否存在这个对象池 if (!poolDic.ContainsKey (name)) { //注册一个对象池加到资源中 Register (name); } subPool = poolDic [name]; return subPool.SubPoolSpwan (); } public void UnSpawn (GameObject obj) { //先判断是否有这个对象所存在的对象池 foreach (SubPool item in poolDic.Values) { if (item.SubPoolContains (obj)) { //让该对象回收 item.SubPoolUnSpwan (obj); break; } } }
/// <summary> /// 接口: /// 用于判断对象的生成与销毁 /// </summary> public interface IControl { //生成对象的方法 void Spawn (); //销毁对象的方法 void UnSpawn (); }
public class BulletScript : MonoBehaviour,IControl { public void Spawn () { // Invoke ("DeleteSelf", 3f); Debug.Log ("从对象池中取出子弹"); } public void UnSpawn () { Debug.Log ("将子弹放对象池中"); } void DeleteSelf () { //回收游戏对象 PoolControl.Instance.UnSpawn (gameObject); //重置子弹的位置 transform.position = Vector3.zero; } void Update () { transform.position += Vector3.forward * 4f * Time.deltaTime; } }
public class PlayerScript : MonoBehaviour { void Update () { if (Input.GetKeyDown (KeyCode.Space)) { PoolControl.Instance.Spwan ("Bullet"); } } }