Unity之设计模式:单例模式和对象池模式

1. 单例模式

单例模式原则:

  1. 只能有一个实例。
  2. 必须自己创建自己。
  3. 必须给所有其他对象提供这一实例。

目的:第一条保证仅有一个实例(私有化构造函数),第二、三条保证提供一个访问它的全局访问点(提供一个供访问的公共方法/属性)。

优点:避免一个全局使用的类被频繁的创建与销毁。

 分类:饿汉式:不去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 }

 

posted @ 2021-11-02 11:32  番茄玛丽  阅读(362)  评论(0编辑  收藏  举报