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

时间:2022-06-27 08:31:12

游戏UI框架设计(二)

--最简版本设计

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

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

2:缓存UI窗体。

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

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

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

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

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

     //UI窗体(位置)类型
public enum UIFormType
{
//普通窗体
Normal,
//固定窗体
Fixed,
//弹出窗体
PopUp
} //UI窗体的显示类型
public enum UIFormShowMode
{
//普通
Normal,
//反向切换
ReverseChange,
//隐藏其他
HideOther
} //UI窗体透明度类型
public enum UIFormLucenyType
{
//完全透明,不能穿透
Lucency,
//半透明,不能穿透
Translucence,
//低透明度,不能穿透
ImPenetrable,
//可以穿透
Pentrate
}

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

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

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

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

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

     /// <summary>
/// UI(窗体)类型
/// </summary>
internal class UIType
{
//是否需要清空“反向切换”
public bool IsClearReverseChange = false;
//UI窗体类型
public UIFormsType UIForms_Type = UIFormsType.Normal;
//UI窗体显示类型
public UIFormsShowMode UIForms_ShowMode = UIFormsShowMode.Normal;
//UI窗体透明度类型
public UIFormsLucencyType UIForms_LucencyType = UIFormsLucencyType.Lucency;
}

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

     public class BaseUIForms : MonoBehaviour
{
/* 字段 */
//当前(基类)窗口的类型
private UIType _CurrentUIType=new UIType(); /* 属性 */
/// <summary>
/// 属性_当前UI窗体类型
/// </summary>
internal UIType CurrentUIType
{
set
{
_CurrentUIType = value;
} get
{
return _CurrentUIType;
}
} //页面显示
public virtual void Display()
{
this.gameObject.SetActive(true);
} //页面隐藏(不在“栈”集合中)
public virtual void Hiding()
{
this.gameObject.SetActive(false);
}
//页面重新显示
public virtual void Redisplay()
{
this.gameObject.SetActive(true);
}
//页面冻结(还在“栈”集合中)
public virtual void Freeze()
{
this.gameObject.SetActive(true);
} }//Class_end

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

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

 public class UIManager : MonoBehaviour {
/* 字段 */
private static UIManager _Instance = null;
//UI窗体预设路径(参数1:窗体预设名称,2:表示窗体预设路径)
private Dictionary<string, string> _DicFormsPaths;
//缓存所有UI窗体
private Dictionary<string, BaseUIForm> _DicALLUIForms;
//当前显示的UI窗体
private Dictionary<string, BaseUIForm> _DicCurrentShowUIForms;
//UI根节点
private Transform _TraCanvasTransfrom = null;
//全屏幕显示的节点
private Transform _TraNormal = null;
//固定显示的节点
private Transform _TraFixed = null;
//弹出节点
private Transform _TraPopUp = null;
//UI管理脚本的节点
private Transform _TraUIScripts = null; /// <summary>
/// 得到实例
/// </summary>
/// <returns></returns>
public static UIManager GetInstance()
{
if (_Instance==null)
{
_Instance = new GameObject("_UIManager").AddComponent<UIManager>();
}
return _Instance;
} //初始化核心数据,加载“UI窗体路径”到集合中。
public void Awake()
{
//字段初始化
_DicALLUIForms=new Dictionary<string, BaseUIForm>();
_DicCurrentShowUIForms=new Dictionary<string, BaseUIForm>();
_DicFormsPaths=new Dictionary<string, string>();
//初始化加载(根UI窗体)Canvas预设
InitRootCanvasLoading();
//得到UI根节点、全屏节点、固定节点、弹出节点
_TraCanvasTransfrom = GameObject.FindGameObjectWithTag(SysDefine.SYS_TAG_CANVAS).transform;
_TraNormal = _TraCanvasTransfrom.Find("Normal");
_TraFixed = _TraCanvasTransfrom.Find("Fixed");
_TraPopUp = _TraCanvasTransfrom.Find("PopUp");
_TraUIScripts = _TraCanvasTransfrom.Find("_ScriptMgr");
//把本脚本作为“根UI窗体”的子节点。
this.gameObject.transform.SetParent(_TraUIScripts, false);
//"根UI窗体"在场景转换的时候,不允许销毁
DontDestroyOnLoad(_TraCanvasTransfrom);
//初始化“UI窗体预设”路径数据
//先写简单的,后面我们使用Json做配置文件,来完善。
if (_DicFormsPaths!=null)
{
_DicFormsPaths.Add("LogonUIForm", @"UIPrefabs\LogonUIForm");
}
} /// <summary>
/// 显示(打开)UI窗体
/// 功能:
/// 1: 根据UI窗体的名称,加载到“所有UI窗体”缓存集合中
/// 2: 根据不同的UI窗体的“显示模式”,分别作不同的加载处理
/// </summary>
/// <param name="uiFormName">UI窗体预设的名称</param>
public void ShowUIForms(string uiFormName)
{
BaseUIForm baseUIForms=null; //UI窗体基类 //参数的检查
if (string.IsNullOrEmpty(uiFormName)) return;
//根据UI窗体的名称,加载到“所有UI窗体”缓存集合中
baseUIForms = LoadFormsToAllUIFormsCatch(uiFormName);
if (baseUIForms == null) return;
//根据不同的UI窗体的显示模式,分别作不同的加载处理
switch (baseUIForms.CurrentUIType.UIForms_ShowMode)
{
case UIFormShowMode.Normal: //“普通显示”窗口模式
//把当前窗体加载到“当前窗体”集合中。
LoadUIToCurrentCache(uiFormName);
break;
case UIFormShowMode.ReverseChange: //需要“反向切换”窗口模式
//更靠后课程进行讲解。
break;
case UIFormShowMode.HideOther: //“隐藏其他”窗口模式
//更靠后课程进行讲解。
break;
default:
break;
}
} #region 私有方法
//初始化加载(根UI窗体)Canvas预设
private void InitRootCanvasLoading()
{
ResourcesMgr.GetInstance().LoadAsset(SysDefine.SYS_PATH_CANVAS, false);
} /// <summary>
/// 根据UI窗体的名称,加载到“所有UI窗体”缓存集合中
/// 功能: 检查“所有UI窗体”集合中,是否已经加载过,否则才加载。
/// </summary>
/// <param name="uiFormsName">UI窗体(预设)的名称</param>
/// <returns></returns>
private BaseUIForm LoadFormsToAllUIFormsCatch(string uiFormsName)
{
BaseUIForm baseUIResult = null; //加载的返回UI窗体基类 _DicALLUIForms.TryGetValue(uiFormsName, out baseUIResult);
if (baseUIResult==null)
{
//加载指定名称的“UI窗体”
baseUIResult = LoadUIForm(uiFormsName);
} return baseUIResult;
} /// <summary>
/// 加载指定名称的“UI窗体”
/// 功能:
/// 1:根据“UI窗体名称”,加载预设克隆体。
/// 2:根据不同预设克隆体中带的脚本中不同的“位置信息”,加载到“根窗体”下不同的节点。
/// 3:隐藏刚创建的UI克隆体。
/// 4:把克隆体,加入到“所有UI窗体”(缓存)集合中。
///
/// </summary>
/// <param name="uiFormName">UI窗体名称</param>
private BaseUIForm LoadUIForm(string uiFormName)
{
string strUIFormPaths = null; //UI窗体路径
GameObject goCloneUIPrefabs = null; //创建的UI克隆体预设
BaseUIForm baseUiForm=null; //窗体基类 //根据UI窗体名称,得到对应的加载路径
_DicFormsPaths.TryGetValue(uiFormName, out strUIFormPaths);
//根据“UI窗体名称”,加载“预设克隆体”
if (!string.IsNullOrEmpty(strUIFormPaths))
{
goCloneUIPrefabs = ResourcesMgr.GetInstance().LoadAsset(strUIFormPaths, false);
}
//设置“UI克隆体”的父节点(根据克隆体中带的脚本中不同的“位置信息”)
if (_TraCanvasTransfrom != null && goCloneUIPrefabs != null)
{
baseUiForm = goCloneUIPrefabs.GetComponent<BaseUIForm>();
if (baseUiForm == null)
{
Debug.Log("baseUiForm==null! ,请先确认窗体预设对象上是否加载了baseUIForm的子类脚本! 参数 uiFormName=" + uiFormName);
return null;
}
switch (baseUiForm.CurrentUIType.UIForms_Type)
{
case UIFormType.Normal: //普通窗体节点
goCloneUIPrefabs.transform.SetParent(_TraNormal, false);
break;
case UIFormType.Fixed: //固定窗体节点
goCloneUIPrefabs.transform.SetParent(_TraFixed, false);
break;
case UIFormType.PopUp: //弹出窗体节点
goCloneUIPrefabs.transform.SetParent(_TraPopUp, false);
break;
default:
break;
} //设置隐藏
goCloneUIPrefabs.SetActive(false);
//把克隆体,加入到“所有UI窗体”(缓存)集合中。
_DicALLUIForms.Add(uiFormName, baseUiForm);
return baseUiForm;
}
else
{
Debug.Log("_TraCanvasTransfrom==null Or goCloneUIPrefabs==null!! ,Plese Check!, 参数uiFormName="+uiFormName);
} Debug.Log("出现不可以预估的错误,请检查,参数 uiFormName="+uiFormName);
return null;
}//Mehtod_end /// <summary>
/// 把当前窗体加载到“当前窗体”集合中
/// </summary>
/// <param name="uiFormName">窗体预设的名称</param>
private void LoadUIToCurrentCache(string uiFormName)
{
BaseUIForm baseUiForm; //UI窗体基类
BaseUIForm baseUIFormFromAllCache; //从“所有窗体集合”中得到的窗体 //如果“正在显示”的集合中,存在整个UI窗体,则直接返回
_DicCurrentShowUIForms.TryGetValue(uiFormName, out baseUiForm);
if (baseUiForm != null) return;
//把当前窗体,加载到“正在显示”集合中
_DicALLUIForms.TryGetValue(uiFormName, out baseUIFormFromAllCache);
if (baseUIFormFromAllCache!=null)
{
_DicCurrentShowUIForms.Add(uiFormName, baseUIFormFromAllCache);
baseUIFormFromAllCache.Display(); //显示当前窗体
}
} #endregion }//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框架)脚本编写完毕,测试成功后效果如下图:

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

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

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