一、简介
1.1、UI基类—UIBase
1.2、UI第二层基类,继承自UIBase,分别为UIWindowBase(所有窗口的基类)、UISceneBase(场景UI基类)
继承自UISceneBase的类都放在UIRoot物体上,而继承自UIWindowBase的类,主要放在窗口上,例如整个登
录注册面板的父物体UIPanel物体之上,类似的。
1.3、三个基本的管理器:LayerUIMgr(UI层级管理器)、SceneUIMgr(场景管UI理器)、WindowUIMgr(窗口
UI管理器)
SceneUIMgr(场景管UI理器):主要用于场景UI加载,即场景UIRoot预制物体的加载。
WindowUIMgr(窗口UI管理器):主要用于例如登录窗口、注册窗口等的预制加载,关闭和销毁。
LayerUIMgr(UI层级管理器):记录一个当前最大深度值,用于设置传入物体的深度层级值。
二、代码
2.1、UIBase

using UnityEngine;
/// <summary>
/// UI基类
/// </summary>
public class UIBase : MonoBehaviour
{
    private void Awake()
    {
        OnAwake();
    }
    void Start()
    {
        #region 给所有的UIButton绑定事件
        UIButton[] btnArr = GetComponentsInChildren<UIButton>(true);//setactive为false的也要获得
        for (int i = 0; i < btnArr.Length; i++)
        {
            UIEventListener.Get(btnArr[i].gameObject).onClick += BtnClick;
        }
        #endregion
        OnStart();
    }
    private void OnDestroy()
    {
        BeforeOnDestory();
    }
    private void BtnClick(GameObject go)
    {
        OnBtnClick(go);
    }
    protected virtual void OnAwake()
    {

    }
    protected virtual void OnStart()
    {

    }
    protected virtual void OnBtnClick(GameObject go)
    {

    }
    protected virtual void BeforeOnDestory()
    {

    }
}

2.2、UIWindowBase(所有窗口的基类)以及UISceneBase(场景UI基类)
2.2.1、UIWindowBase

using UnityEngine;
/// <summary>
/// 所有窗口的基类
/// </summary>
public class UIWindowBase : UIBase
{
    /// <summary>
    /// 挂点类型,挂在哪个容器位置下
    /// </summary>
    public WindowUIContainerType containerType = WindowUIContainerType.Center;
    /// <summary>
    /// 显示类型
    /// </summary>
    public WindowShowStyle showStyle = WindowShowStyle.Normal;
    /// <summary>
    /// 打开或者关闭动画效果持续时间
    /// </summary>
    public float duration = 0.2f;
    /// <summary>
    /// 当前窗口类型
    /// </summary>
    [HideInInspector]
    public WindowUIType CurrentUIType;
    /// <summary>
    /// 下一个要打开的窗口
    /// </summary>
    public WindowUIType m_NextOpenWindow = WindowUIType.None;
    /// <summary>
    /// 关闭当前自己
    /// </summary>
    protected virtual void Close()
    {
        WindowUIMgr.Instance.CloseWindow(CurrentUIType);
    }
    /// <summary>
    /// 销毁自身之前调用
    /// </summary>
    protected override void BeforeOnDestory()
    {
        if (m_NextOpenWindow == WindowUIType.None) return;
        WindowUIMgr.Instance.OpenWindow(m_NextOpenWindow);
    }
}

2.2.2、UISceneBase(场景UI基类)

using UnityEngine;
/// <summary>
/// 场景UI基类
/// </summary>
public class UISceneBase : UIBase
{
    /// <summary>
    /// 容器_居中
    /// </summary>
    public Transform Container_Center;
}

2.2.3、例举一些继承自这两个类的一些实现
2.2.3.1、UISceneLogonCtrl 挂载在Scene_LogOn场景的UIRoot物体上。用于显示进入场景就加载打开登录窗口

using System.Collections;
using UnityEngine;
public class UISceneLogonCtrl : UISceneBase
{

    protected override void OnStart()
    {
        base.OnStart();
        //加载登录窗口       
        StartCoroutine(OpenLogOnWindow());
    }

    private IEnumerator OpenLogOnWindow()
    {
        yield return new WaitForSeconds(0.5f);
        GameObject obj = WindowUIMgr.Instance.OpenWindow(WindowUIType.LogOn);
    }
    private void Update()
    {
    }
}

2.2.3.2、UI_PanelLogonCtrl 挂在在登录窗口面板最外层父物体上

using UnityEngine;
/// <summary>
/// 登录窗口UI控制器
/// </summary>
public class UI_PanelLogonCtrl : UIWindowBase
{
    /// <summary>
    /// 昵称
    /// </summary>
    [SerializeField]
    private UIInput m_InputNockName;
    /// <summary>
    /// 密码
    /// </summary>
    [SerializeField]
    private UIInput m_InputPwd;
    /// <summary>
    /// 提示
    /// </summary>
    [SerializeField]
    private UILabel m_libTip;
    #region OnBtnClick 重写基类OnBtnClick
    /// <summary>
    /// 重写基类OnBtnClick
    /// </summary>
    /// <param name="go"></param>
    protected override void OnBtnClick(GameObject go)
    {
        Debug.Log("登录窗口Btn调用");
        switch (go.name)
        {
            case "BtnLog":
                BtnLogOn();
                break;
            case "BtnReg":
                BtnReg();
                break;
        }
    }
    #endregion
    /// <summary>
    /// 我要注册按钮
    /// </summary>
    void BtnReg()
    {
        //this.Close();
        //m_NextOpenWindow = WindowUIType.Reg;
        WindowUIMgr.Instance.OpenWindow(WindowUIType.Reg);
    }
    /// <summary>
    /// 登录按钮
    /// </summary>
    void BtnLogOn()
    {
        string nickName = this.m_InputNockName.value.Trim();
        string pwd = m_InputPwd.value.Trim();
        string oldNickName = PlayerPrefs.GetString(GlobalInit.MMO_NICKNAME);
        string oldPwd = PlayerPrefs.GetString(GlobalInit.MMO_PWD);
        if (nickName == string.Empty || pwd == string.Empty)
        {
            m_libTip.text = "密码或者昵称不能为空";
            return;
        }
        if (oldNickName != nickName || oldPwd != pwd)
        {
            m_libTip.text = "您输入的账号或者密码错误";
            return;
        }
        GlobalInit.Instance.CurrRoleNickName = nickName;
        SceneMgr.Instance.LoadToCity();
    }
}

2.3管理类 WindowUIMgr(窗口管理类)、LayerUIMgr(UI层级管理器)、SceneUIMgr(场景管UI理器)
2.3.1、WindowUIMgr

using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 窗口UI管理器,窗口加载等方法
/// </summary>
public class WindowUIMgr : Singleton<WindowUIMgr>
{
    /// <summary>
    /// 当前场景中的窗口存贮表
    /// </summary>
    private Dictionary<WindowUIType, UIWindowBase> m_DicWindow = new Dictionary<WindowUIType, UIWindowBase>();
    public int OpenWindowCount
    {
        get
        {
            return m_DicWindow.Count;
        }
    }
    #region LoadWindow 打开窗口
    /// <summary>
    ///  打开窗口,窗口命名书写为Panel+枚举类型名=预制体的名称
    /// </summary>
    /// <param name="type">窗口类型</param>
    public GameObject OpenWindow(WindowUIType type)
    {
        if (type == WindowUIType.None) return null;
        GameObject obj = null;
        if (!m_DicWindow.ContainsKey(type))
        {
            //枚举名要与预制体一致
            obj = ResourcesMgr.Instance.Load(ResourcesMgr.ResourcesType.UIWindows, string.Format("Panel{0}", type.ToString()), true);
            if (obj == null) return null;
            UIWindowBase windowbase = obj.GetComponent<UIWindowBase>();
            if (windowbase == null) return null;
            windowbase.CurrentUIType = type;
            m_DicWindow.Add(type, windowbase);
            Transform transParent = null;
            switch (windowbase.containerType)
            {
                case WindowUIContainerType.Center:
                    Debug.Log("????");
                    transParent = SceneUIMgr.Instance.CurrentUIScene.Container_Center;
                    break;
                case WindowUIContainerType.TL: break;
                case WindowUIContainerType.TR: break;
                case WindowUIContainerType.BL: break;
                case WindowUIContainerType.BR: break;

            }
            obj.transform.parent = transParent;
            obj.transform.localPosition = Vector3.zero;
            obj.transform.localScale = Vector3.one;
            NGUITools.SetActive(obj, false);
            StartShowWindow(windowbase, true);
        }
        else
        {
            obj = m_DicWindow[type].gameObject;
        }
        LayerUIMgr.Instance.SetLayer(obj);


        return obj;
    }
    #endregion
    #region 开始打开窗口
    private void StartShowWindow(UIWindowBase windowbase, bool isOpen)
    {
        switch (windowbase.showStyle)
        {
            case WindowShowStyle.Normal:
                ShowNormal(windowbase, isOpen);
                break;
            case WindowShowStyle.CenterToBig:
                ShowCenterToBig(windowbase, isOpen);
                break;
            case WindowShowStyle.FromDown:
                ShowFromDir(windowbase, 1, isOpen);
                break;
            case WindowShowStyle.FromLeft:
                ShowFromDir(windowbase, 2, isOpen);
                break;
            case WindowShowStyle.FromRight:
                ShowFromDir(windowbase, 3, isOpen);
                break;
            case WindowShowStyle.FromTop:
                ShowFromDir(windowbase, 0, isOpen);
                break;

        }
    }
    #endregion
    #region 关闭窗口
    /// <summary>
    /// 关闭窗口
    /// </summary>
    /// <param name="windowbase"></param>
    public void CloseWindow(WindowUIType type)
    {
        if (m_DicWindow.ContainsKey(type))
        {
            StartShowWindow(m_DicWindow[type], false);
        }
    }
    #endregion
    #region 各种打开效果
    private void ShowNormal(UIWindowBase windowbase, bool isOpen)
    {
        if (isOpen)
        {
            NGUITools.SetActive(windowbase.gameObject, true);
        }
        else
        {
            DestroyWindow(windowbase);
        }
    }
    /// <summary>
    /// 从中间变大
    /// </summary>
    /// <param name="obj"></param>
    /// <param name="isOpen"></param>
    private void ShowCenterToBig(UIWindowBase windowbase, bool isOpen)
    {
        TweenScale ts = windowbase.gameObject.GetOrCreatComponent<TweenScale>();
        ts.animationCurve = GlobalInit.Instance.UIAnimationCurve;
        ts.from = Vector3.zero;//开始大小
        ts.to = Vector3.one;//结束大小
        ts.duration = windowbase.duration;//持续时间
        ts.SetOnFinished(() =>//动画完成之后调用事件
        {
            if (!isOpen)
            {
                DestroyWindow(windowbase);
            }
        });
        NGUITools.SetActive(windowbase.gameObject, true);
        if (!isOpen) ts.Play(isOpen);//如果isOpen=false,即我想要关闭窗口,动画运行反方向
    }
    /// <summary>
    /// 从不同的方向加载
    /// </summary>
    /// <param name="windowbase"></param>
    /// <param name="dirType">0--从上往下,1-从下往上,2--从左向右,3---从右到左</param>
    /// <param name="isOpen"></param>
    private void ShowFromDir(UIWindowBase windowbase, int dirType, bool isOpen)
    {
        TweenPosition tp = windowbase.gameObject.GetOrCreatComponent<TweenPosition>();
        tp.animationCurve = GlobalInit.Instance.UIAnimationCurve;

        Vector3 from = Vector3.zero;
        switch (dirType)
        {
            case 0:
                from = new Vector3(0, 1000, 0);
                break;
            case 1:
                from = new Vector3(0, -1000, 0);
                break;
            case 2:
                from = new Vector3(-1000, 0, 0);
                break;
            case 3:
                from = new Vector3(1000, 0, 0);
                break;

        }
        tp.from = from;//开始大小
        tp.to = Vector3.one;//结束大小

        tp.duration = windowbase.duration;//持续时间
        tp.SetOnFinished(() =>//动画完成之后调用事件
        {
            if (!isOpen)
            {
                DestroyWindow(windowbase);
            }
        });
        NGUITools.SetActive(windowbase.gameObject, true);
        if (!isOpen) tp.Play(isOpen);//如果isOpen=false,即我想要关闭窗口,动画运行反方向
    }
    #endregion
    #region 销毁窗口
    /// <summary>
    /// 销毁窗口
    /// </summary>
    /// <param name="obj"></param>
    private void DestroyWindow(UIWindowBase windowbase)
    {
        m_DicWindow.Remove(windowbase.CurrentUIType);

        GameObject.Destroy(windowbase.gameObject);

        LayerUIMgr.Instance.CheckOpenWindow();
    }
    #endregion


}

2.3.2、SceneUIMgr

using UnityEngine;
using System.Collections;
/// <summary>
/// 场景管UI理器
/// </summary>
public class SceneUIMgr : Singleton <SceneUIMgr>
{
    public UISceneBase CurrentUIScene;
    #region LoadSceneUI 加载场景UI
    /// <summary>
    /// 加载场景UI
    /// </summary>
    /// <param name="type"></param>
    /// <returns></returns>
    public GameObject LoadSceneUI(SceneUIType type)
    {
        GameObject obj = null;
        switch (type )
        {
            case SceneUIType.LogOn:
                obj = ResourcesMgr.Instance.Load(ResourcesMgr.ResourcesType.UIScene, GameConst.UIRoot_LogOnScene);
                CurrentUIScene = obj.GetComponent<UISceneLogonCtrl>();
                break;
            case SceneUIType.Loading:break;
            case SceneUIType.MainCity:
                obj = ResourcesMgr.Instance.Load(ResourcesMgr.ResourcesType.UIScene, GameConst.UIRoot_CityScene);
                CurrentUIScene = obj.GetComponent<UISceneCityCtrl>();
                break;
        }
        return obj ;
    }
    #endregion
}

2.3.3、LayerUIMgr

using UnityEngine;
using System.Collections;

/// <summary>
/// UI层级管理器
/// </summary>
public class LayerUIMgr : Singleton <LayerUIMgr> {

    /// <summary>
    /// UIPanel层级深度
    /// </summary>
    private int m_UIPanelDepth = 50;
	public void Reset()
    {
        m_UIPanelDepth = 50;
    }
    /// <summary>
    /// 检查窗口数量,如果没有打开的窗口,重置深度
    /// </summary>
    public void CheckOpenWindow()
    {
        if(WindowUIMgr.Instance .OpenWindowCount==0)
        {
            Reset();
        }
    }
    public void SetLayer(GameObject obj)
    {
        m_UIPanelDepth += 1;
        UIPanel[] panArr = obj.GetComponentsInChildren<UIPanel>();
        if(panArr .Length >0)
        {
            for (int i = 0; i < panArr .Length ; i++)
            {
                panArr[i].depth += m_UIPanelDepth;
            }
        }
    }
}

2.4、思路
每个场景有一个场景管理类,如Scene_LogOn场景具有一个类LogOnSceneCtrl.cs类,进入场景就加载场景UI的UIRoot物体。而每个UIRoot上面都挂载一个UISceneBase的子类,该子类中可以在加载时的start方法里加载一些马上显示的窗口之类的。

using UnityEngine;
 using System.Collections;
 public class LogOnSceneCtrl : MonoBehaviour {private void Awake()
{
    SceneUIMgr.Instance.LoadSceneUI(SceneUIType.LogOn);
}}

2.5、其他类
2.5.1、单例类

using UnityEngine;
using System.Collections;
using System;

public class Singleton<T>:IDisposable where T:new ()
{
    private static T instance;
    public static T Instance
    {
        get
        {
            if(instance ==null )
            {
                instance = new T();
            }
            return instance;
        }
    }

    public virtual  void Dispose()
    {
       
    }
}

2.5.2、枚举类

#region WindowUIType 窗口类型
/// <summary>
/// 窗口类型
/// </summary>
public enum WindowUIType
{
    /// <summary>
    /// 未设置
    /// </summary>
    None,
    /// <summary>
    /// 登录窗口
    /// </summary>
    LogOn,
    /// <summary>
    /// 注册窗口
    /// </summary>
    Reg,
    /// <summary>
    /// 角色信息窗口
    /// </summary>
    RoleInfo,
}
#endregion
#region WindowShowStyle 窗口打开方式
/// <summary>
/// 窗口打开方式
/// </summary>
public enum WindowShowStyle
{
    /// <summary>
    /// 正常打开
    /// </summary>
    Normal,
    /// <summary>
    /// 从中间放大
    /// </summary>
    CenterToBig,
    /// <summary>
    /// 从上往下
    /// </summary>
    FromTop,
    /// <summary>
    /// 从下往上
    /// </summary>
    FromDown,
    /// <summary>
    /// 从左往右
    /// </summary>
    FromLeft,
    /// <summary>
    /// 从右向左
    /// </summary>
    FromRight,
}
#endregion
#region  WindowUIContainerType UI容器类型
/// <summary>
/// UI容器类型
/// </summary>
public enum WindowUIContainerType
{
    /// <summary>
    /// 左上
    /// </summary>
    TL,
    //右上
    TR,
    /// <summary>
    /// 左下
    /// </summary>
    BL,
    /// <summary>
    /// 右下
    /// </summary>
    BR,
    /// <summary>
    /// 居中
    /// </summary>
    Center,
}
#endregion
#region SceneUIType 场景UI类型
/// <summary>
/// 场景UI类型
/// </summary>
public enum SceneUIType
{
    /// <summary>
    /// 登录
    /// </summary>
    LogOn,
    /// <summary>
    /// 加载
    /// </summary>
    Loading,
    /// <summary>
    /// 主城
    /// </summary>
    MainCity,
}
#endregion
#region 场景类型
/// <summary>
/// 场景类型
/// </summary>
public enum SceneType
{
    LogOn,
    City,
}
#endregion 

#region 角色类型
/// <summary>
/// 角色类型
/// </summary>
public enum RoleType
{
    /// <summary>
    /// 未设置
    /// </summary>
    None = 0,
    /// <summary>
    /// 当前玩家
    /// </summary>
    MainPlayer = 1,
    /// <summary>
    /// 怪
    /// </summary>
    Monster = 2
}
#endregion

#region 角色状态
/// <summary>
/// 角色状态
/// </summary>
public enum RoleState
{
    /// <summary>
    /// 未设置
    /// </summary>
    None = 0,
    /// <summary>
    /// 待机
    /// </summary>
    Idle = 1,
    /// <summary>
    /// 跑
    /// </summary>
    Run = 2,
    /// <summary>
    /// 攻击
    /// </summary>
    Attack = 3,
    /// <summary>
    /// 受伤
    /// </summary>
    Hurt = 4,
    /// <summary>
    /// 死亡
    /// </summary>
    Die = 5,
}
#endregion

#region  角色动画名称
/// <summary>
/// 角色动画名称
/// </summary>
public enum RoleAnimatorName
{
    Idle_Normal,
    Idle_Fight,
    Run,
    Hurt,
    Die,
    PhyAttack1,
    PhyAttack2,
    PhyAttack3
}
#endregion

/// <summary>
/// 动画切换参数变量名
/// </summary>
public enum ToAnimatorCondition
{
    ToIdleNormal,
    ToIdleFight,
    ToRun,
    ToHurt,
    ToDie,
    ToPhyAttack,
    CurrState,
}