游戲UI框架設計(四)
--模態窗體管理
我們在開發UI窗體時,對於“彈出窗體”往往因為需要玩家優先處理彈出小窗體,則要求玩家不能(無法)點擊“父窗體”,這種窗體就是典型的“模態窗體”。在此筆者設計了四種模式類型:完全透明、半透明、低透明度、透明且可以穿透。

(透明不能穿透)

(半透明不能穿透)

(低透明度,不能穿透)
對於“模態窗體”的基本實現原理是:
在彈出窗體的后面增加一層“UI遮罩窗體”,當需要彈出特定模態窗體時,腳本自動控制“UI遮罩窗體”的“層級”,把彈出模特窗體與普通窗體之間進行隔離,起到突出顯示與遮擋用戶點擊其他窗體的作用。原理如下圖所示:

在上圖左邊的層級視圖中,有一個“_UIMaskPanel”的特殊窗體,這就是“UI遮罩窗體”,在不需要彈出顯示的時候,這個窗體是“禁用”狀態。 為了更好適用不同開發需求,對於彈出窗體,我們上面定義了關於彈出窗體的不同性質: 完全透明、半透明、低透明度、透明且可以穿透。 這四種類型功能的實現原理是控制“_UIMaskPanel”的顏色數值以及透明度實現的,見下圖所示:

說明: 上圖右邊屬性就是“UI遮罩窗體”的屬性欄,筆者通過腳本控制Image組件的Color 組件,來實現"模態窗體”的不同顯示性質。
原理講完,貼出控制代碼如下:
1 /*** 2 * 3 * Title: "SUIFW" UI框架項目 4 * 主題: UI遮罩管理器 5 * Description: 6 * 功能: 負責“彈出窗體”模態顯示實現 7 * 8 * Date: 2017 9 * Version: 0.1版本 10 * Modify Recoder: 11 * 12 * 13 */ 14 using System.Collections; 15 using System.Collections.Generic; 16 using System.Net.Mime; 17 using UnityEngine; 18 using UnityEngine.UI; 19 20 namespace SUIFW 21 { 22 public class UIMaskMgr : MonoBehaviour { 23 /* 字段 */ 24 //本腳本私有單例 25 private static UIMaskMgr _Instance = null; 26 //UI根節點對象 27 private GameObject _GoCanvasRoot = null; 28 //UI腳本節點對象 29 private Transform _TraUIScriptsNode = null; 30 //頂層面板 31 private GameObject _GoTopPanel; 32 //遮罩面板 33 private GameObject _GoMaskPanel; 34 //UI攝像機 35 private Camera _UICamera; 36 //UI攝像機原始的“層深” 37 private float _OriginalUICameralDepth; 38 39 //得到實例 40 public static UIMaskMgr GetInstance() 41 { 42 if (_Instance==null) 43 { 44 _Instance = new GameObject("_UIMaskMgr").AddComponent<UIMaskMgr>(); 45 } 46 return _Instance; 47 } 48 49 50 51 52 void Awake() 53 { 54 //得到UI根節點對象、腳本節點對象 55 _GoCanvasRoot = GameObject.FindGameObjectWithTag(SysDefine.SYS_TAG_CANVAS); 56 _TraUIScriptsNode = UnityHelper.FindTheChildNode(_GoCanvasRoot, SysDefine.SYS_SCRIPTMANAGER_NODE); 57 //把本腳本實例,作為“腳本節點對象”的子節點。 58 UnityHelper.AddChildNodeToParentNode(_TraUIScriptsNode,this.gameObject.transform); 59 //得到“頂層面板”、“遮罩面板” 60 _GoTopPanel = _GoCanvasRoot; 61 _GoMaskPanel = UnityHelper.FindTheChildNode(_GoCanvasRoot, "_UIMaskPanel").gameObject; 62 //得到UI攝像機原始的“層深” 63 _UICamera = GameObject.FindGameObjectWithTag("_TagUICamera").GetComponent<Camera>(); 64 if (_UICamera != null) 65 { 66 //得到UI攝像機原始“層深” 67 _OriginalUICameralDepth = _UICamera.depth; 68 } 69 else 70 { 71 Debug.Log(GetType()+"/Start()/UI_Camera is Null!,Please Check! "); 72 } 73 } 74 75 /// <summary> 76 /// 設置遮罩狀態 77 /// </summary> 78 /// <param name="goDisplayUIForms">需要顯示的UI窗體</param> 79 /// <param name="lucenyType">顯示透明度屬性</param> 80 public void SetMaskWindow(GameObject goDisplayUIForms,UIFormLucenyType lucenyType=UIFormLucenyType.Lucency) 81 { 82 //頂層窗體下移 83 _GoTopPanel.transform.SetAsLastSibling(); 84 //啟用遮罩窗體以及設置透明度 85 switch (lucenyType) 86 { 87 //完全透明,不能穿透 88 case UIFormLucenyType.Lucency: 89 print("完全透明"); 90 _GoMaskPanel.SetActive(true); 91 Color newColor1=new Color(255/255F,255/255F,255/255F,0F/255F); 92 _GoMaskPanel.GetComponent<Image>().color = newColor1; 93 break; 94 //半透明,不能穿透 95 case UIFormLucenyType.Translucence: 96 print("半透明"); 97 _GoMaskPanel.SetActive(true); 98 Color newColor2 = new Color(220/255F, 220/255F, 220/255F, 50/255F); 99 _GoMaskPanel.GetComponent<Image>().color = newColor2; 100 break; 101 //低透明,不能穿透 102 case UIFormLucenyType.ImPenetrable: 103 print("低透明"); 104 _GoMaskPanel.SetActive(true); 105 Color newColor3=new Color(50/255F,50/255F,50/255F,200F/255F); 106 _GoMaskPanel.GetComponent<Image>().color = newColor3; 107 break; 108 //可以穿透 109 case UIFormLucenyType.Pentrate: 110 print("允許穿透"); 111 if (_GoMaskPanel.activeInHierarchy) 112 { 113 _GoMaskPanel.SetActive(false); 114 } 115 break; 116 117 default: 118 break; 119 } 120 121 122 123 //遮罩窗體下移 124 _GoMaskPanel.transform.SetAsLastSibling(); 125 //顯示窗體的下移 126 goDisplayUIForms.transform.SetAsLastSibling(); 127 //增加當前UI攝像機的層深(保證當前攝像機為最前顯示) 128 if (_UICamera!=null) 129 { 130 _UICamera.depth = _UICamera.depth + 100; //增加層深 131 } 132 133 } 134 135 /// <summary> 136 /// 取消遮罩狀態 137 /// </summary> 138 public void CancelMaskWindow() 139 { 140 //頂層窗體上移 141 _GoTopPanel.transform.SetAsFirstSibling(); 142 //禁用遮罩窗體 143 if (_GoMaskPanel.activeInHierarchy) 144 { 145 //隱藏 146 _GoMaskPanel.SetActive(false); 147 } 148 149 //恢復當前UI攝像機的層深 150 if (_UICamera != null) 151 { 152 _UICamera.depth = _OriginalUICameralDepth; //恢復層深 153 } 154 } 155 156 157 } 158 }
關於上述定義的UIMaskMgr.cs 腳本代碼 ,筆者在“BaseUIForm.cs” 中做了封裝,使其可以在框架中自動管理,無需框架外客戶程序的處理。BaseUIForm.cs 代碼如下:
1 /*** 2 * 3 * Title: "SUIFW" UI框架項目 4 * 主題: UI窗體的父類 5 * Description: 6 * 功能:定義所有UI窗體的父類。 7 * 定義四個生命周期 8 * 9 * 1:Display 顯示狀態。 10 * 2:Hiding 隱藏狀態 11 * 3:ReDisplay 再顯示狀態。 12 * 4:Freeze 凍結狀態。 13 * 14 * 15 * Date: 2017 16 * Version: 0.1版本 17 * Modify Recoder: 18 * 19 * 20 */ 21 using System.Collections; 22 using System.Collections.Generic; 23 using System.ComponentModel.Design; 24 using UnityEngine; 25 26 namespace SUIFW 27 { 28 public class BaseUIForm : MonoBehaviour { 29 /*字段*/ 30 private UIType _CurrentUIType=new UIType(); 31 32 /* 屬性*/ 33 //當前UI窗體類型 34 public UIType CurrentUIType 35 { 36 get { return _CurrentUIType; } 37 set { _CurrentUIType = value; } 38 } 39 40 41 #region 窗體的四種(生命周期)狀態 42 43 /// <summary> 44 /// 顯示狀態 45 /// </summary> 46 public virtual void Display() 47 { 48 this.gameObject.SetActive(true); 49 //設置模態窗體調用(必須是彈出窗體) 50 if (_CurrentUIType.UIForms_Type==UIFormType.PopUp) 51 { 52 UIMaskMgr.GetInstance().SetMaskWindow(this.gameObject,_CurrentUIType.UIForm_LucencyType); 53 } 54 } 55 56 /// <summary> 57 /// 隱藏狀態 58 /// </summary> 59 public virtual void Hiding() 60 { 61 this.gameObject.SetActive(false); 62 //取消模態窗體調用 63 if (_CurrentUIType.UIForms_Type == UIFormType.PopUp) 64 { 65 UIMaskMgr.GetInstance().CancelMaskWindow(); 66 } 67 } 68 69 /// <summary> 70 /// 重新顯示狀態 71 /// </summary> 72 public virtual void Redisplay() 73 { 74 this.gameObject.SetActive(true); 75 //設置模態窗體調用(必須是彈出窗體) 76 if (_CurrentUIType.UIForms_Type == UIFormType.PopUp) 77 { 78 UIMaskMgr.GetInstance().SetMaskWindow(this.gameObject, _CurrentUIType.UIForm_LucencyType); 79 } 80 } 81 82 /// <summary> 83 /// 凍結狀態 84 /// </summary> 85 public virtual void Freeze() 86 { 87 this.gameObject.SetActive(true); 88 } 89 90 91 #endregion 92 93 94 } 95 }
以上所講解的是大體實現思路,還有很多的小細節由於時間關系沒有披露,所以特提供下載鏈接,供感興趣的開發者研究討論。歡迎大家提供進一步完善的思路與建議。
本游戲UI框架(截止到以上部分)下載參考鏈接: 鏈接:http://pan.baidu.com/s/1nv4plFV 密碼:6o0n
先講解到這,我們下次講解: 游戲UI框架設計(五):配置管理與日志系統
