游戏UI框架设计(四) : 模态窗体管理
游戏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框架设计(五):配置管理与日志系统