创建两个枚举如下
/// <summary>
/// UI窗体透明度类型
/// </summary>
public enum UIFormLucenyType
{
/// <summary>
/// 完全透明
/// </summary>
Lucency,
/// <summary>
/// 半透明
/// </summary>
Translucence,
/// <summary>
/// 低透明
/// </summary>
ImPenetrable,
/// <summary>
/// 纯黑
/// </summary>
Opacification,
}
/// <summary>
/// UI窗体层级
/// </summary>
public enum UILayer
{
/// <summary>
/// 基础层 大厅、登录等基础界面 0-100
/// </summary>
NormalLayer = 0,
/// <summary>
/// 二级弹窗 例如商城 背包等等 101-200
/// </summary>
TwoPopLayer = 101,
/// <summary>
/// 三级弹窗 例如 跑马灯、弹窗奖励 二次确认弹窗等等 201-300
/// </summary>
ThreePopLayer = 201,
/// <summary>
/// 四级弹窗 例如 断网重连 之类的 301-400
/// </summary>
FourPopLayer = 301,
}
在创建一个脚本Tool.cs
using UnityEngine;
public class Tools
{
/// <summary>
/// 创建物体
/// </summary>
/// <param name="obj">原物体</param>
/// <param name="parent">父节点</param>
/// <param name="isRecover">是否重置大小坐标</param>
/// <param name="isOffset">是否重置UI偏移</param>
public static GameObject LocalInstantiate(GameObject obj,Transform parent = null,bool isRecover = true,bool isOffset = false)
{
GameObject o = GameObject.Instantiate(obj);
if (parent)
o.transform.parent = parent;
if (isRecover)
{
SetRecover(o,isOffset);
}
return o;
}
/// <summary>
/// 重置数据
/// </summary>
/// <param name="o"></param>
public static void SetRecover(GameObject o,bool isOffset = false)
{
if (o == null) return;
o.transform.localPosition = Vector3.zero;
o.transform.localScale = Vector3.one;
if (isOffset)
{
RectTransform rect = o.GetComponent<RectTransform>();
if (rect)
{
rect.offsetMax = new Vector2(0, 0);
rect.offsetMin = new Vector2(0, 0);
}
}
}
/// <summary>
/// 查找物体
/// </summary>
/// <param name="parent"></param>
/// <param name="path"></param>
/// <returns></returns>
public static Transform FindChild(GameObject parent,string path)
{
if (parent == null || path == "") return null;
return parent.transform.Find(path);
}
}
创建一个UI的基类UIBase.cs 所有的UI都继承自此脚本
using DG.Tweening;
using System;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// UI基类
/// </summary>
public class UIBase : MonoBehaviour
{
/// <summary>
/// UI窗体透明度类型
/// </summary>
[Header("UI窗体透明度类型")]
public UIFormLucenyType UIForm_LucenyType = UIFormLucenyType.Translucence;
/// <summary>
/// UI窗体透明度类型
/// </summary>
[Header("UI窗体层级")]
public UILayer m_UILayer = UILayer.NormalLayer;
/// <summary>
/// UI数据
/// </summary>
public object[] m_Data;
/// <summary>
/// 存储所有注册的事件ID 用来关闭UI时清除消息监听
/// </summary>
private List<int> m_EventIDs;
/// <summary>
/// UI打开之后播放的动画效果
/// </summary>
public virtual void ShowAnim()
{
transform.DOScale(new Vector3(1.02f, 1.02f, 1.02f), 0.2f).OnComplete(() =>
{
transform.DOScale(Vector3.one, 0.1f).OnComplete(() =>
{
this.OnShow();
});
});
}
/// <summary>
/// UI刚刚加载出来回调
/// </summary>
public virtual void OnLoad(object[] data)
{
this.m_EventIDs = new List<int>();
this.m_Data = data;
//UI动画播放完动画之后做的处理
this.ShowAnim();
}
/// <summary>
/// UI加载完毕并且动画播放完之后的回调
/// </summary>
public virtual void OnShow()
{
//UI打开完毕之后注册消息
this.OnRegister();
}
/// <summary>
/// UI注册消息
/// </summary>
public virtual void OnRegister()
{
}
/// <summary>
/// 注册消息
/// </summary>
/// <param name="eventID"></param>
/// <param name="bindFunc"></param>
public void AddRegister(int eventID, OnActionHandler bindFunc)
{
this.m_EventIDs.Add(eventID);
EventDispatcher.AddEventListener(this, eventID, bindFunc);
}
public virtual void OnHide()
{
this.gameObject.SetActive(false);
}
/// <summary>
/// 关闭UI
/// </summary>
public virtual void OnClose()
{
EventDispatcher.RemoveEventListener(this,this.m_EventIDs.ToArray());
}
}
在创建一个UI管理器
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
public class UIMgr : MonoBehaviour
{
public static UIMgr Ins;
/// <summary>
/// 缓存所有的UI窗体
/// </summary>
private Dictionary<string, UIBase> m_AllUI;
/// <summary>
/// UI根节点
/// </summary>
private GameObject _Root = null;
/// <summary>
/// Canvas
/// </summary>
public Transform _CanvasTran = null;
/// <summary>
/// UI节点
/// </summary>
private Transform _TraNormal = null;
/// <summary>
/// 遮罩节点
/// </summary>
private Image _MaskNode = null;
/// <summary>
/// 栈 结构表示的是 当前弹出的ui窗体的集合
/// </summary>
private Stack<UIBase> _StaCurrentUIbase;
#region 初始化
private void Awake()
{
DontDestroyOnLoad(this);
Ins = this;
this.Init();
}
void Init()
{
_StaCurrentUIbase = new Stack<UIBase>();
m_AllUI = new Dictionary<string, UIBase>();
//加载UI根节点
_CanvasTran = GameObject.Find("Canvas").transform;
GameObject o = AssetBundleMgr.Ins.LoadAsset<GameObject>("ui_uiroot", "uiroots", FileType.OBJ);
_Root = Tools.LocalInstantiate(o, _CanvasTran, true, true);
//拿到节点下的UI节点
_TraNormal = Tools.FindChild(_Root, "normal");
_MaskNode = Tools.FindChild(_Root, "mask").GetComponent<Image>();
}
#endregion
#region 供外部调用接口
/// <summary>
/// 打开UI
/// </summary>
/// <param name="uiname">ui名字</param>
/// <param name="uimodule">ui预制体放置的模块</param>
/// <param name="data">打开UI后要传递的参数</param>
public void Show(string uiname, string uimodule = "ui_base", params object[] data)
{
//UI已激活则不处理
if (this.Exists(uiname) != null) return;
if (string.IsNullOrEmpty(uiname) || string.IsNullOrEmpty(uimodule)) return;
//UI窗体基类
UIBase baseUI = this.LoadUI(uiname, uimodule, data);
if (baseUI == null) return;
//遮罩
this.ShowMask(baseUI);
if(baseUI.m_UILayer != UILayer.NormalLayer)
{
//添加UI层
DepthUI dep = baseUI.gameObject.AddComponent<DepthUI>();
dep.SetLayer(baseUI.m_UILayer);
//将2级弹窗及以上全部加入到栈中
_StaCurrentUIbase.Push(baseUI);
}
//UI刚创建出来之后做的处理
baseUI.OnLoad(data);
}
/// <summary>
/// 关闭UI
/// </summary>
/// <param name="uiname">ui名字</param>
public void Close(string uiname)
{
//UI窗体基类
UIBase baseUI = null;
if (string.IsNullOrEmpty(uiname)) return;
//所有UI窗体缓存如果没有记录,则直接返回。
this.m_AllUI.TryGetValue(uiname, out baseUI);
if (baseUI == null) return;
//将栈顶UI出栈 ui遮罩切换到上一层ui
this.PopUIForms();
baseUI.OnClose();
//删除之前清除自身动画
baseUI.gameObject.transform.DOKill();
GameObject.Destroy(baseUI.gameObject);
m_AllUI.Remove(uiname);
}
/// <summary>
/// 检查该UI是否处于开启状态
/// </summary>
/// <param name="uiname"></param>
/// <returns></returns>
public UIBase Exists(string uiname)
{
UIBase baseUI = null;
//获取该窗口信息
m_AllUI.TryGetValue(uiname, out baseUI);
return baseUI;
}
#endregion
#region 内部调用接口
/// <summary>
/// 加载UI
/// </summary>
/// <param name="uiname">UI窗体名称</param>
/// <param name="uimodule">ui模块</param>
/// <param name="data">ui传递的数据</param>
private UIBase LoadUI(string uiname, string uimodule = "ui_base", params object[] data)
{
UIBase baseui = null;
GameObject goCloneUIPrefabs = Instantiate(AssetBundleMgr.Ins.LoadAsset<GameObject>(uimodule, uiname, FileType.OBJ));
if (_Root != null && goCloneUIPrefabs != null)
{
baseui = goCloneUIPrefabs.GetComponent<UIBase>();
if (baseui == null)
{
Debug.Log("baseui==null uiname=" + uiname);
baseui = goCloneUIPrefabs.AddComponent<UIBase>();
}
goCloneUIPrefabs.transform.SetParent(_TraNormal);
Tools.SetRecover(goCloneUIPrefabs);
m_AllUI.Add(uiname, baseui);
return baseui;
}
Debug.Log("Load error uiFormName=" + uiname);
return null;
}
/// <summary>
/// 显示遮罩
/// </summary>
/// <param name="baseui"></param>
private void ShowMask(UIBase baseui)
{
if (_MaskNode == null || baseui == null)
{
if (_MaskNode != null)
{
_MaskNode.transform.parent = _Root.transform;
_MaskNode.gameObject.SetActive(false);
}
return;
}
_MaskNode.gameObject.SetActive(true);
_MaskNode.transform.parent = baseui.transform;
_MaskNode.transform.SetAsFirstSibling();
switch (baseui.UIForm_LucenyType)
{
case UIFormLucenyType.Lucency:
Debug.Log("==== 完全透明");
_MaskNode.color = new Color(0, 0, 0, 0f / 255f);
break;
case UIFormLucenyType.Translucence:
Debug.Log("==== 半透明");
_MaskNode.color = new Color(0, 0, 0, 50f / 255f);
break;
case UIFormLucenyType.ImPenetrable:
Debug.Log("==== 低透明");
_MaskNode.color = new Color(0, 0, 0, 200f / 255f);
break;
case UIFormLucenyType.Opacification:
Debug.Log("==== 纯黑");
_MaskNode.color = new Color(0, 0, 0, 255f);
break;
default:
break;
}
}
/// <summary>
/// UI窗体出栈逻辑
/// </summary>
private void PopUIForms()
{
//出栈窗体的下一个窗体逻辑
UIBase nextuibase = null;
if (_StaCurrentUIbase.Count >= 2)
{
//出栈逻辑
UIBase uibase = _StaCurrentUIbase.Pop();
//出栈的窗体,进行隐藏处理
uibase.OnHide();
//获取栈顶元素
nextuibase = _StaCurrentUIbase.Peek();
}
else if (_StaCurrentUIbase.Count == 1)
{
//出栈
UIBase uibase = _StaCurrentUIbase.Pop();
//出栈的窗体,进行隐藏处理
uibase.OnHide();
}
this.ShowMask(nextuibase);
}
#endregion
}
在创建一个事件管理类EventDispatcher.cs
using System.Collections.Generic;
using System.Linq;
/// <summary>
/// 委托原型
/// </summary>
/// <param name="obj"></param>
public delegate void OnActionHandler(params object[] obj);
public class EventDispatcher
{
#region 消息ID
public static int Test = 10001;
public static int Test01 = 10002;
#endregion
/// <summary>
/// 监听字典
/// </summary>
private static Dictionary<int, List<EventStruct>> events;
/// <summary>
/// 添加监听
/// </summary>
/// <param name="baseui"></param>
/// <param name="eventID"></param>
/// <param name="onAction"></param>
public static void AddEventListener(UIBase baseui,int eventID, OnActionHandler onAction)
{
if(events == null)events = new Dictionary<int, List<EventStruct>>();
EventStruct ev = new EventStruct();
ev.m_Baseui = baseui;
ev.m_Func = onAction;
if (!events.ContainsKey(eventID))
{
events.Add(eventID, new List<EventStruct>() { ev });
}
else
{
List<EventStruct> list = events[eventID];
bool b = false;
for (int i = 0; i < list.Count; i++)
{
if (list[i].m_Baseui == baseui)
{
b = true;
break;
}
}
if (!b)
{
list.Add(ev);
events[eventID] = list;
}
}
}
/// <summary>
/// 移除监听
/// </summary>
/// <param name="baseui"></param>
/// <param name="eventIDs"></param>
public static void RemoveEventListener(UIBase baseui, int[] eventIDs)
{
if (events == null) return;
if (eventIDs != null && eventIDs.Length > 0)
{
for (int i = 0; i < eventIDs.Length; i++)
{
List<EventStruct> ls = events[eventIDs[i]];
for (int j = 0; j < ls.Count; j++)
{
if (ls[j].m_Baseui == baseui)
{
ls.RemoveAt(j);
break;
}
}
if (ls.Count <= 0)
{
events.Remove(eventIDs[i]);
}
else
{
events[eventIDs[i]] = ls;
}
}
}
}
/// <summary>
/// 消息派发
/// </summary>
/// <param name="eventID">监听ID</param>
/// <param name="data">参数</param>
public static void Dispatcher(int eventID, params object[] data)
{
if (events == null) return;
if (events.ContainsKey(eventID))
{
List<EventStruct> list = events[eventID];
for (int i = 0; i < list.Count; i++)
{
if (list[i] != null)
{
list[i].m_Func(data);
}
}
}
}
}
public class EventStruct
{
public OnActionHandler m_Func;
public UIBase m_Baseui;
}
创建一个DepthUI.cs
using UnityEngine;
using UnityEngine.UI;
public class DepthUI : MonoBehaviour
{
public int order = 0;
public bool isUi = true;
public void SetLayer(UILayer layer, bool isUi = true)
{
this.order = (int)layer;
if (isUi)
{
Canvas canvas = this.GetComponent<Canvas>();
if (canvas == null)
{
canvas = this.gameObject.AddComponent<Canvas>();
this.gameObject.AddComponent<GraphicRaycaster>();
}
canvas.overrideSorting = true;
canvas.sortingOrder = order;
}
else
{
Renderer[] renders = this.GetComponentsInChildren<Renderer>();
foreach (Renderer render in renders)
{
render.sortingOrder = order;
}
}
}
}
创建一个测试脚本Demo.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Demo : MonoBehaviour
{
public AudioSource audio;
public Transform tran;
// Start is called before the first frame update
void Start()
{
this.gameObject.AddComponent<AssetBundleMgr>();
//bundle加载
//AssetBundleManager.Ins.InitModel(AssetLoadMode.AssetBundler);
//Editor加载
AssetBundleMgr.Ins.InitModel(AssetLoadMode.Editor);
this.gameObject.AddComponent<UIMgr>();
#region 测试数据
//异步
//AssetBundleManager.Ins.LoadAsyncAsset<AudioClip>("audio_man", "bg", FileType.MP3, (obj) =>
//{
// audio.clip = obj;
// audio.Play();
//});
//同步
//AudioClip o = AssetBundleManager.Ins.LoadAsset<AudioClip>("audio_man", "bg", FileType.MP3);
//audio.clip = o;
//audio.Play();
//异步
//AssetBundleManager.Ins.LoadAsyncAsset<GameObject>("ui_common", "card", FileType.OBJ, (obj) =>
//{
// obj = Instantiate(obj);
// obj.transform.parent = tran;
// obj.transform.localPosition = Vector3.zero;
// obj.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
//});
#endregion
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.W))
{
UIMgr.Ins.Show("card", "ui_common");
}
if (Input.GetKeyDown(KeyCode.Space))
{
UIMgr.Ins.Close("card");
}
if (Input.GetKeyDown(KeyCode.E))
{
UIMgr.Ins.Show("gamemain", "ui_gamemain");
}
if (Input.GetKeyDown(KeyCode.R))
{
UIMgr.Ins.Close("gamemain");
}
if (Input.GetKeyDown(KeyCode.A))
{
UIMgr.Ins.Show("gameover", "ui_gameover", "zyt");
}
if (Input.GetKeyDown(KeyCode.S))
{
UIMgr.Ins.Close("gameover");
}
if (Input.GetKeyDown(KeyCode.Y))
{
EventDispatcher.Dispatcher(EventDispatcher.Test);
EventDispatcher.Dispatcher(EventDispatcher.Test01);
}
if (Input.GetKeyDown(KeyCode.U))
{
EventDispatcher.Dispatcher(EventDispatcher.Test,1,2,3,"sssss");
EventDispatcher.Dispatcher(EventDispatcher.Test01,4,5,6,"bbbb");
}
}
}
测试结果如下
如下是root节点内容