Unity之设计模式:单例模式和对象池模式
1. 单例模式
单例模式原则:
- 只能有一个实例。
- 必须自己创建自己。
- 必须给所有其他对象提供这一实例。
目的:第一条保证仅有一个实例(私有化构造函数),第二、三条保证提供一个访问它的全局访问点(提供一个供访问的公共方法/属性)。
优点:避免一个全局使用的类被频繁的创建与销毁。
分类:饿汉式:不去new一个新的,而是在Awake里 instance=this。
懒汉式:需要用的时候,发现单例为空,再实例化一个。
1 public class SingleTon<T> : MonoBehaviour where T : Component 2 { 3 private static T instance; 4 public static T Instance //提供对外访问的属性 5 { 6 get 7 { 8 if (instance == null) //如果没有实例化,那就实例化一个 9 { 10 if (FindObjectsOfType<T>().Length > 1) //查找挂载了这个脚本的物体,如果超过1个,多个物体挂载了不符合单例模式 11 Debug.LogError("instance count>1"); 12 instance = FindObjectOfType<T>(); //挂载在一个物体身上了 13 if (instance == null) //没有挂载在任何物体身上 14 { 15 GameObject go = new GameObject(); //创建一个空物体 16 go.name = typeof(T).ToString(); //物体名就是类型名 17 instance = go.AddComponent<T>(); //把这个脚本挂载上去 18 } 19 } 20 return instance; 21 } 22 } 23 }
2. 对象池模式
目的:需要频繁的创建和销毁的物体,比如怪兽、金币、障碍物... 频繁的创建和销毁非常耗费资源,不如游戏一开始就创建出来一堆,先隐藏起来,要使用的时候取消隐藏(从池子中取出),不使用了再隐藏(放回池子)。
案例:结合单例模式,做一个道具生成和销毁对象池。要求主池子掌控所有物体的生成和销毁(主池子只有一个),子池子提供共有的方法和特征(取出、放回)。
1)提前把道具的预制体做好,放在资源文件夹下。
2)写子池子逻辑:从子池子中取出、放回子池子、放回所有物体
1 public class SubPool 2 { 3 List<GameObject> subPool = new List<GameObject>(); 4 GameObject prefab; 5 6 public SubPool(GameObject pref) 7 { 8 prefab = pref; 9 } 10 public GameObject OutPool() //从池子中取出 11 { 12 GameObject obj = null; 13 foreach (GameObject go in subPool) //找到一个被隐藏的物体,取出来 14 { 15 if (go.activeSelf == false) 16 obj = go; 17 } 18 if (obj == null) //池子里没有被隐藏的物体了,预存的不够用了,再生成一个 19 { 20 obj = GameObject.Instantiate(prefab); 21 subPool.Add(obj); //把新生成的也加到池子里 22 } 23 obj.SetActive(true); //把找到的这个物体显示出来(取出来) 24 return obj; 25 } 26 public void InputPool() //放回池子中 27 { 28 if (subPool.Count > 0) 29 { 30 foreach(GameObject go in subPool) 31 { 32 if (go.activeSelf == true) 33 { 34 go.SetActive(false); 35 break; 36 } 37 } 38 } 39 } 40 public void InputAllObject() 41 { 42 foreach (GameObject go in subPool) 43 { 44 if (go.activeSelf == true) 45 InputPool(); 46 } 47 } 48 }
3)写主池子逻辑,管理所有子池子。
1 public class ObjManager : SingleTon<ObjManager> 2 { 3 private Dictionary<string, SubPool> PoolDic = new Dictionary<string, SubPool>(); //用字典掌管所有的子池子 4 5 public GameObject OutPool(string name) 6 { 7 if (PoolDic.ContainsKey(name) == false) //如果主池子不包含该对象,new一个子池子,添加进主池子中 8 { 9 GameObject obj = Resources.Load("Prefabs/" + name) as GameObject; 10 SubPool subpool = new SubPool(obj); 11 PoolDic.Add(name, subpool); 12 } 13 SubPool subPool = PoolDic[name]; 14 return subPool.OutPool(); 15 } 16 public void InputPool(string objName) 17 { 18 PoolDic[objName].InputPool(); 19 } 20 public void InputAllObject() 21 { 22 foreach (SubPool sp in PoolDic.Values) 23 sp.InputAllObject(); 24 } 25 }