游戏UI框架设计(二) : 最简版本设计

游戏UI框架设计(二)

--最简版本设计

 

  为降低难度决定先讲解一个最简版本,阐述UI框架的核心设计理念。这里先定义三个核心功能:

   1:UI窗体的自动加载功能。

   2:缓存UI窗体。

   3:窗体生命周期(状态)管理。

     UI框架设计主要目的,就是尽可能的完成一些与具体游戏功能逻辑无关的一些底层事务性的功能实现。这些功能最好是自动或者是半自动的实现,无须客户程序(调用框架的程序)再去过多处理与关心。

    对于以上功能,笔者定义了UI框架的相关四个核心类:

  •    BaseUIForms    基础UI窗体脚本(父类,其他窗体都继承此脚本)
  •    UIManger.cs    UI窗体管理器脚本(框架核心脚本)
  •    UIType         窗体类型 (引用窗体的重要属性[枚举类型])
  •    SysDefine      系统定义类(包含框架中使用到的枚举类型、委托事件、系统常量、接口等)

  在SysDefine 文件中,定义本框架三个核心枚举类型

 1     //UI窗体(位置)类型
 2     public enum UIFormType
 3     {
 4         //普通窗体
 5         Normal,   
 6         //固定窗体                              
 7         Fixed,
 8         //弹出窗体
 9         PopUp
10     }
11     
12     //UI窗体的显示类型
13     public enum UIFormShowMode
14     {
15         //普通
16         Normal,
17         //反向切换
18         ReverseChange,
19         //隐藏其他
20         HideOther
21     }
22 
23     //UI窗体透明度类型
24     public enum UIFormLucenyType
25     {
26         //完全透明,不能穿透
27         Lucency,
28         //半透明,不能穿透
29         Translucence,
30         //低透明度,不能穿透
31         ImPenetrable,
32         //可以穿透
33         Pentrate    
34     }

 

 上述三个核心枚举类型,解释如下:

  1.  UIFormType 枚举类型,表示Unity层级视图中挂载不同类型窗体的空节点。这里Fixed 表示固定窗体,表示可以挂载"非全屏非弹出窗体",例如RPG游戏项目中的“英雄信息”窗体等。
  2.  UIFormShowMode 枚举,表示窗体不同的显示方式。Normal 类型表示窗体与其他窗体可以并列显示; HideOther类型表示窗体显示的时候,需要隐藏所有其他窗体; ReverseChange 窗体主要应用与"弹出窗体",维护多个弹出窗体的层级关系。
  3.  UIFormLucenyType 枚举,是定义弹出“模态窗体”不同透明度的类型。

  上图是我们定义的UGUI 中的“根窗体”预设 "Canvas",在Untiy的层级视图中,可以看到我们定义了若干空节点,用于不同类型的UI窗体加载到不同的“根窗体”预设中,实现不同显示效果。

  定义 UIType 类,主要是引用定义的三个核心枚举,方便使用 。代码如下:

 1     /// <summary>
 2     /// UI(窗体)类型
 3     /// </summary>
 4     internal class UIType
 5     {
 6         //是否需要清空“反向切换”
 7         public bool IsClearReverseChange = false;
 8         //UI窗体类型
 9         public UIFormsType UIForms_Type = UIFormsType.Normal;
10         //UI窗体显示类型
11         public UIFormsShowMode UIForms_ShowMode = UIFormsShowMode.Normal;
12         //UI窗体透明度类型
13         public UIFormsLucencyType UIForms_LucencyType = UIFormsLucencyType.Lucency;
14     }

 

  定义基础UI窗体 BaseUIForms 脚本,代码如下:

 1     public class BaseUIForms : MonoBehaviour
 2     {
 3         /*  字段  */
 4         //当前(基类)窗口的类型
 5         private UIType _CurrentUIType=new UIType();
 6 
 7         /*  属性  */
 8         /// <summary>
 9         /// 属性_当前UI窗体类型
10         /// </summary>
11         internal UIType CurrentUIType
12         {
13             set
14             {
15                 _CurrentUIType = value;
16             }
17 
18             get
19             {
20                 return _CurrentUIType;
21             }
22         }
23 
24         //页面显示
25         public virtual void Display()
26         {
27             this.gameObject.SetActive(true);
28         }
29         
30         //页面隐藏(不在“栈”集合中)
31         public virtual void Hiding()
32         {
33             this.gameObject.SetActive(false);
34         }
35         //页面重新显示
36         public virtual void Redisplay()
37         {
38             this.gameObject.SetActive(true);
39         }
40         //页面冻结(还在“栈”集合中)
41         public virtual void Freeze()
42         {
43             this.gameObject.SetActive(true);
44         } 
45 
46     }//Class_end

 

  上述代码中,主要定义了UI窗体基类的四个重要虚方法,分别对应窗体的打开显示、隐藏、重新显示、窗体冻结(即:窗体显示在其他窗体下面)。方便窗体在不同状态下,针对不同的行为进一步做处理操作。例如,当窗体为“隐藏”与“冻结”状态时,如果此窗体有针对远程服务的网络连接(Socket套接字)时,则需要关闭网络连接,以节省网络资源。

  定义“UI管理器”(UIManager.cs) 脚本,这是UI框架中的核心脚本,主要负责UI窗体的加载、缓存、以及对于“UI窗体基类”的各种生命周期的操作(显示、隐藏、重新显示、冻结)。

  1 public class UIManager : MonoBehaviour {
  2         /* 字段 */
  3         private static UIManager _Instance = null;
  4         //UI窗体预设路径(参数1:窗体预设名称,2:表示窗体预设路径)
  5         private Dictionary<string, string> _DicFormsPaths; 
  6         //缓存所有UI窗体
  7         private Dictionary<string, BaseUIForm> _DicALLUIForms;
  8         //当前显示的UI窗体
  9         private Dictionary<string, BaseUIForm> _DicCurrentShowUIForms;
 10         //UI根节点
 11         private Transform _TraCanvasTransfrom = null;
 12         //全屏幕显示的节点
 13         private Transform _TraNormal = null;
 14         //固定显示的节点
 15         private Transform _TraFixed = null;
 16         //弹出节点
 17         private Transform _TraPopUp = null;
 18         //UI管理脚本的节点
 19         private Transform _TraUIScripts = null;
 20 
 21 
 22         /// <summary>
 23         /// 得到实例
 24         /// </summary>
 25         /// <returns></returns>
 26         public static UIManager GetInstance()
 27         {
 28             if (_Instance==null)
 29             {
 30                 _Instance = new GameObject("_UIManager").AddComponent<UIManager>();
 31             }
 32             return _Instance;
 33         }
 34 
 35         //初始化核心数据,加载“UI窗体路径”到集合中。
 36         public void Awake()
 37         {
 38             //字段初始化
 39             _DicALLUIForms=new Dictionary<string, BaseUIForm>();
 40             _DicCurrentShowUIForms=new Dictionary<string, BaseUIForm>();
 41             _DicFormsPaths=new Dictionary<string, string>();
 42             //初始化加载(根UI窗体)Canvas预设
 43             InitRootCanvasLoading();
 44             //得到UI根节点、全屏节点、固定节点、弹出节点
 45             _TraCanvasTransfrom = GameObject.FindGameObjectWithTag(SysDefine.SYS_TAG_CANVAS).transform;
 46             _TraNormal = _TraCanvasTransfrom.Find("Normal");
 47             _TraFixed = _TraCanvasTransfrom.Find("Fixed");
 48             _TraPopUp = _TraCanvasTransfrom.Find("PopUp");
 49             _TraUIScripts = _TraCanvasTransfrom.Find("_ScriptMgr");
 50             //把本脚本作为“根UI窗体”的子节点。
 51             this.gameObject.transform.SetParent(_TraUIScripts, false);
 52             //"根UI窗体"在场景转换的时候,不允许销毁
 53             DontDestroyOnLoad(_TraCanvasTransfrom);
 54             //初始化“UI窗体预设”路径数据
 55             //先写简单的,后面我们使用Json做配置文件,来完善。
 56             if (_DicFormsPaths!=null)
 57             {
 58                 _DicFormsPaths.Add("LogonUIForm", @"UIPrefabs\LogonUIForm");
 59             }
 60         }
 61 
 62         /// <summary>
 63         /// 显示(打开)UI窗体
 64         /// 功能:
 65         /// 1: 根据UI窗体的名称,加载到“所有UI窗体”缓存集合中
 66         /// 2: 根据不同的UI窗体的“显示模式”,分别作不同的加载处理
 67         /// </summary>
 68         /// <param name="uiFormName">UI窗体预设的名称</param>
 69         public void ShowUIForms(string uiFormName)
 70         {
 71             BaseUIForm baseUIForms=null;                    //UI窗体基类
 72 
 73             //参数的检查
 74             if (string.IsNullOrEmpty(uiFormName)) return;
 75             //根据UI窗体的名称,加载到“所有UI窗体”缓存集合中
 76             baseUIForms = LoadFormsToAllUIFormsCatch(uiFormName);
 77             if (baseUIForms == null) return;
 78             //根据不同的UI窗体的显示模式,分别作不同的加载处理
 79             switch (baseUIForms.CurrentUIType.UIForms_ShowMode)
 80             {                    
 81                 case UIFormShowMode.Normal:                 //“普通显示”窗口模式
 82                     //把当前窗体加载到“当前窗体”集合中。
 83                     LoadUIToCurrentCache(uiFormName);
 84                     break;
 85                 case UIFormShowMode.ReverseChange:          //需要“反向切换”窗口模式
 86                     //更靠后课程进行讲解。
 87                     break;
 88                 case UIFormShowMode.HideOther:              //“隐藏其他”窗口模式
 89                     //更靠后课程进行讲解。
 90                     break;
 91                 default:
 92                     break;
 93             }
 94         }
 95 
 96         #region 私有方法
 97         //初始化加载(根UI窗体)Canvas预设
 98         private void InitRootCanvasLoading()
 99         {
100             ResourcesMgr.GetInstance().LoadAsset(SysDefine.SYS_PATH_CANVAS, false);
101         }
102 
103         /// <summary>
104         /// 根据UI窗体的名称,加载到“所有UI窗体”缓存集合中
105         /// 功能: 检查“所有UI窗体”集合中,是否已经加载过,否则才加载。
106         /// </summary>
107         /// <param name="uiFormsName">UI窗体(预设)的名称</param>
108         /// <returns></returns>
109         private BaseUIForm LoadFormsToAllUIFormsCatch(string uiFormsName)
110         {
111             BaseUIForm baseUIResult = null;                 //加载的返回UI窗体基类
112 
113             _DicALLUIForms.TryGetValue(uiFormsName, out baseUIResult);
114             if (baseUIResult==null)
115             {
116                 //加载指定名称的“UI窗体”
117                 baseUIResult = LoadUIForm(uiFormsName);
118             }
119 
120             return baseUIResult;
121         }
122 
123         /// <summary>
124         /// 加载指定名称的“UI窗体”
125         /// 功能:
126         ///    1:根据“UI窗体名称”,加载预设克隆体。
127         ///    2:根据不同预设克隆体中带的脚本中不同的“位置信息”,加载到“根窗体”下不同的节点。
128         ///    3:隐藏刚创建的UI克隆体。
129         ///    4:把克隆体,加入到“所有UI窗体”(缓存)集合中。
130         /// 
131         /// </summary>
132         /// <param name="uiFormName">UI窗体名称</param>
133         private BaseUIForm LoadUIForm(string uiFormName)
134         {
135             string strUIFormPaths = null;                   //UI窗体路径
136             GameObject goCloneUIPrefabs = null;             //创建的UI克隆体预设
137             BaseUIForm baseUiForm=null;                     //窗体基类
138 
139 
140             //根据UI窗体名称,得到对应的加载路径
141             _DicFormsPaths.TryGetValue(uiFormName, out strUIFormPaths);
142             //根据“UI窗体名称”,加载“预设克隆体”
143             if (!string.IsNullOrEmpty(strUIFormPaths))
144             {
145                 goCloneUIPrefabs = ResourcesMgr.GetInstance().LoadAsset(strUIFormPaths, false);
146             }
147             //设置“UI克隆体”的父节点(根据克隆体中带的脚本中不同的“位置信息”)
148             if (_TraCanvasTransfrom != null && goCloneUIPrefabs != null)
149             {
150                 baseUiForm = goCloneUIPrefabs.GetComponent<BaseUIForm>();
151                 if (baseUiForm == null)
152                 {
153                     Debug.Log("baseUiForm==null! ,请先确认窗体预设对象上是否加载了baseUIForm的子类脚本! 参数 uiFormName=" + uiFormName);
154                     return null;
155                 }
156                 switch (baseUiForm.CurrentUIType.UIForms_Type)
157                 {
158                     case UIFormType.Normal: //普通窗体节点
159                         goCloneUIPrefabs.transform.SetParent(_TraNormal, false);
160                         break;
161                     case UIFormType.Fixed: //固定窗体节点
162                         goCloneUIPrefabs.transform.SetParent(_TraFixed, false);
163                         break;
164                     case UIFormType.PopUp: //弹出窗体节点
165                         goCloneUIPrefabs.transform.SetParent(_TraPopUp, false);
166                         break;
167                     default:
168                         break;
169                 }
170 
171                 //设置隐藏
172                 goCloneUIPrefabs.SetActive(false);
173                 //把克隆体,加入到“所有UI窗体”(缓存)集合中。
174                 _DicALLUIForms.Add(uiFormName, baseUiForm);
175                 return baseUiForm;
176             }
177             else
178             {
179                 Debug.Log("_TraCanvasTransfrom==null Or goCloneUIPrefabs==null!! ,Plese Check!, 参数uiFormName="+uiFormName); 
180             }
181 
182             Debug.Log("出现不可以预估的错误,请检查,参数 uiFormName="+uiFormName);
183             return null;
184         }//Mehtod_end
185 
186         /// <summary>
187         /// 把当前窗体加载到“当前窗体”集合中
188         /// </summary>
189         /// <param name="uiFormName">窗体预设的名称</param>
190         private void LoadUIToCurrentCache(string uiFormName)
191         {
192             BaseUIForm baseUiForm;                          //UI窗体基类
193             BaseUIForm baseUIFormFromAllCache;              //从“所有窗体集合”中得到的窗体
194 
195             //如果“正在显示”的集合中,存在整个UI窗体,则直接返回
196             _DicCurrentShowUIForms.TryGetValue(uiFormName, out baseUiForm);
197             if (baseUiForm != null) return;
198             //把当前窗体,加载到“正在显示”集合中
199             _DicALLUIForms.TryGetValue(uiFormName, out baseUIFormFromAllCache);
200             if (baseUIFormFromAllCache!=null)
201             {
202                 _DicCurrentShowUIForms.Add(uiFormName, baseUIFormFromAllCache);
203                 baseUIFormFromAllCache.Display();           //显示当前窗体
204             }
205         }
206 
207         #endregion
208 
209     }//class_end

 

UI管理器脚本解释如下:

一:上述代码中重要字段的解释如下:
    1:  “_DicFormsPaths” 表示“UI窗体预设路径”集合,负责缓存所有UI窗体预设的名称与对应资源路径的关系。
  2: “ _DicALLUIForms” 表示“所有UI窗体”集合,负责缓存已经加载过的所有UI窗体名称以及与之对应的UI窗体。
  3: “_DicCurrentShowUIForms”表示“当前正在显示”集合,负责控制正在显示UI窗体的内部逻辑。
  4: UI管理器脚本中的“_TraCanvasTransfrom”、“_TraNormal”、“_TraFixed”、“_TraPopUp”、“_TraUIScripts”,分别表示Unity层级视图中的根结点、普通节点、固定节点、弹出节点、管理脚本节点,这些节点是加载UI窗体的不同类型的父节点,用于各种UI窗体的管理工作。

二:上述代码中重要方法的解释如下:

  1: ShowUIForms()  是外部程序调用本框架的对外公共方法,负责加载、缓存、打开与显示制定窗体名称的UI窗体预设。
  2: LoadFormsToAllUIFormsCatch() 是根据UI窗体的名称,加载到“所有UI窗体”缓存集合中。
  3: LoadUIToCurrentCache() 是把当前窗体加载到“当前窗体”集合中。

  上述(UI框架)脚本编写完毕,测试成功后效果如下图:

 

  为广大读者进一步了解与熟悉本框架,特提供下载链接:https://pan.baidu.com/s/1eTA8rHS 密码:4x6e

 

  本篇就先写到这,下篇 "游戏UI框架设计(3)_窗体的层级管理" 继续。

 

 

posted @ 2017-02-21 10:17  刘国柱老师  阅读(23911)  评论(16编辑  收藏  举报