转自:https://www.cnblogs.com/LiuGuozhu/p/6517791.html
游戏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();
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();
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 ///
76 /// 设置遮罩状态
77 ///
78 /// 需要显示的UI窗体
79 /// 显示透明度属性
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().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().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().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 ///
136 /// 取消遮罩状态
137 ///
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 ///
44 /// 显示状态
45 ///
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 ///
57 /// 隐藏状态
58 ///
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 ///
70 /// 重新显示状态
71 ///
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 ///
83 /// 冻结状态
84 ///
85 public virtual void Freeze()
86 {
87 this.gameObject.SetActive(true);
88 }
89
90
91 #endregion
92
93
94 }
95 }
以上所讲解的是大体实现思路,还有很多的小细节由于时间关系没有披露,所以特提供下载链接,供感兴趣的开发者研究讨论。欢迎大家提供进一步完善的思路与建议。