1. 程式人生 > >Unity3d 簡單實現 NGUI UI系統

Unity3d 簡單實現 NGUI UI系統

首先定義兩個配置表:
UILevel.txt

層級ID    層級名稱    層級起始深度  鎖定層級(1,鎖定層級,不會自動更新Panel深度)  層級描述
UILeveID    UILevelName UILevelDepth    UILevelLock UILevelDes
1   PanelPanel  0   0   常用面板,如主介面,匹配面板等等
2   TipsPanel   1000    0   tips面板
3   FixedPanel  1500    0   loading介面等等,金幣等等

將UI分為3個層級,用於顯示UI層次

UIConfig.txt 定義UI相關屬性

UIID    UI描述    UI型別    UI層級    UI是否會被銷燬(0不會銷燬,1會銷燬)    UI存在時間  UI路徑    UI名稱    UI鎖定層級(1不會自動修改層級)
UIID    UIDes   UIType  UILevel UICanDestroy    UILife  UIPath  UIName  UILockDepth
1001    登入UI    Login   1   0   0   UI/Parfabs/ LoginPanel  0
1002    伺服器選擇UI Login   1   0   0   UI/Parfabs/ ServerPanel 0
1003    角色選擇介面  Login   3
0 0 UI/Parfabs/ CreateRolePanel 0 1004 載入介面 Game 3 0 0 UI/Parfabs/ LoadingPanel 0 2001 遊戲大廳 Game 1 0 0 UI/Parfabs/ MainPanel 0 2002 頂部資訊面板 Game 3 0 0 UI/Parfabs/ TopPanel 0 2003 商城介面 Game 1 0 0 UI/Parfabs/ MallPanel 0 2004 揹包面板 Game 1 1 10 UI/Parfabs/
BagPanel 0 2005 機械廠介面 Game 1 1 10 UI/Parfabs/ FactoryPanel 0 2006 劇情介面 Game 1 1 10 UI/Parfabs/ CheckPointPanel 0 2007 地圖編輯介面 Game 1 1 10 UI/Parfabs/ EditorMapPanel 0 2008 戰鬥UI Game 1 1 10 UI/Parfabs/ FightPanel 0 2009 匹配模式選擇介面 Game 1 1 10 UI/Parfabs/ MatchTypePanel 0 2010 匹配組選擇介面 Game 1 1 10 UI/Parfabs/ MatchTypeGourpPanel 0 2011 組隊介面 Game 1 1 10 UI/Parfabs/ TeamPanel 0 2012 匹配結果介面 Game 2 1 10 UI/Parfabs/ MatchResPanel 0 2013 英雄選擇介面 Game 1 1 10 UI/Parfabs/ SelHeroPanel 0 2014 道具資訊介面 Game 2 1 10 UI/Parfabs/ PropsInfoPanel 0 2015 戰鬥載入介面 Fight 1 1 10 UI/Parfabs/ FightLoadPanel 0

頂一個列舉型別,用來控制所有UIid

public enum UIType
{
    /// <summary>
    /// 登入註冊面板
    /// </summary>
    LoginPanel = 1001,
    /// <summary>
    /// 伺服器面板
    /// </summary>
    ServerPanel = 1002,

    /// <summary>
    /// 角色選擇面板
    /// </summary>
    SelectRolePanel = 1003,

    /// <summary>
    /// 載入面板
    /// </summary>
    LoadingPanel = 1004,

    /// <summary>
    /// 遊戲大廳
    /// </summary>
    MainPanel = 2001,
    /// <summary>
    /// 遊戲模式面板
    /// </summary>
    TopPanel = 2002,
    /// <summary>
    /// 組隊面板
    /// </summary>
    MallPanel = 2003,
    /// <summary>
    /// 揹包面板
    /// </summary>
    BagPanel = 2004,
    /// <summary>
    /// 機械廠面板
    /// </summary>
    FactoryPanel = 2005,
    /// <summary>
    /// 劇情面板
    /// </summary>
    CheckPointPanel = 2006,
    /// <summary>
    /// 地圖編輯面板
    /// </summary>
    EditorMapPanel = 2007,
    /// <summary>
    /// 戰鬥UI
    /// </summary>
    FightPanel = 2008,
    /// <summary>
    /// 匹配模式選擇
    /// </summary>
    MatchTypePanel = 2009,
    /// <summary>
    /// 匹配模式組選擇
    /// </summary>
    MatchTypeGroupPanel = 2010,
    /// <summary>
    /// 組隊面板
    /// </summary>
    TeamPanel = 2011,
    /// <summary>
    /// 匹配結果面板
    /// </summary>
    MatchResPanel = 2012,
    /// <summary>
    /// 選擇英雄面板
    /// </summary>
    SelHeroPanel = 2013,
    /// <summary>
    /// 道具資訊面板
    /// </summary>
    PropsInfoPanel = 2014,
    /// <summary>
    /// 戰鬥服連接面板
    /// </summary>
    FightLoadPanel = 2015,
    /// <summary>
    /// 網路連線失敗
    /// </summary>
    NetConnectFaildPanel = 5001,

}

抽象類 UIBase.cs 是所有UI的基類,所有UI類均需要繼承此類

using UnityEngine;
using System.Collections;

public abstract class UIBase : MonoBehaviour {

    /// <summary>
    /// UIID
    /// </summary>
    public UIType UIType { get; set; }
    /// <summary>
    /// UI配置資訊
    /// </summary>
    public UIConfig UIConfig { get; set; }
    /// <summary>
    ///上一個UI資料
    /// </summary>
    private object[] PreUIData { get; set; }
    /// <summary>
    /// 上一個UI
    /// </summary>
    private UIBase PreUIBase { get; set; }
    /// <summary>
    /// 是否為開啟狀態
    /// </summary>
    public bool IsOpen { get; private set; }
    /// <summary>
    /// 上一次操作時間
    /// </summary>
    private System.DateTime OpenTime;

    /// <summary>
    /// 是否檢測
    /// </summary>
    private bool isDetection = false;

    /// <summary>
    /// 開啟UI
    /// </summary>
    /// <param name="data"></param>
    public void OpenUI(UIBase preUI,params object[] data)
    {
        IsOpen = true;
        this.gameObject.SetActive(true);
        PreUIBase = preUI;
        PreUIData = data;
        OpenTime = System.DateTime.Now;
        isDetection = false;
        OnOpenAni();
    }
    /// <summary>
    /// 開啟UI動畫
    /// </summary>
    /// <param name="data"></param>
    public virtual void OnOpenAni(params object[] data)
    {
        OnEnter(data);
    }

    /// <summary>
    /// 開啟UI
    /// </summary>
    public void OpenUI()
    {
        this.gameObject.SetActive(true);
        OpenTime = System.DateTime.Now;
        isDetection = false;
        OnEnter(PreUIData);
    }
    /// <summary>
    /// 當更新
    /// </summary>
    /// <param name="data"></param>
    public void OnUpdate(params object[] data)
    {
        UpdateUI(data);
    }

    protected virtual void UpdateUI(params object[] data) {}

    /// <summary>
    /// 關閉UI動畫
    /// </summary>
    public virtual void OnCloseAni()
    {
        OnClose();
    }
    /// <summary>
    /// 關閉UI
    /// </summary>
    protected void OnClose()
    {
        OnExit();
        IsOpen = false;
        isDetection = true;
        this.gameObject.SetActive(false);
    }


    /// <summary>
    /// 獲取開啟時間
    /// </summary>
    public System.DateTime GetOpenTime
    {
        get {
            return OpenTime;
        }
    }

    /// <summary>
    /// 初始化UI
    /// </summary>
    /// <param name="data"></param>
    public abstract void OnInit(params object[] data);

    /// <summary>
    /// 進入UI
    /// </summary>
    /// <param name="data"></param>
    protected abstract void OnEnter(params object[] data);

    /// <summary>
    /// 退出UI
    /// </summary>
    protected abstract void OnExit();

    /// <summary>
    /// 關閉UI
    /// </summary>
    protected void Close()
    {
        UIManager.Instance.CloseUI(UIType);
    }

    /// <summary>
    /// 開啟上一層UI
    /// </summary>
    protected void OpenPreUI()
    {
        if(PreUIBase!=null)
            UIManager.Instance.OpenPreUI(PreUIBase,PreUIData);
    }
}

UIManager.cs 為UI管理類,包括開啟UI,關閉UI等操作

using UnityEngine;
using System.Collections.Generic;
using System.Collections;
using System;

public enum UIFilter
{
    All,
    Open,
    Close,
}

public class UIManager : MonoBehaviour {

    private static UIManager _instance;
    public static UIManager Instance
    {
        get {
            return _instance;
        }
    }

    /// <summary>
    /// UI快取
    /// </summary>
    private Dictionary<UIType, UIBase> uiCache = new Dictionary<UIType, UIBase>();
    /// <summary>
    /// 當前顯示的主UI
    /// </summary>
    public UIBase CurUiBase { get;private set; }
    /// <summary>
    /// loading 介面
    /// </summary>
    public LoadingPanel LoadPanel { get; private set; }
    /// <summary>
    /// UI層級
    /// </summary>
    private Dictionary<int, Transform> uiLevel = new Dictionary<int, Transform>();


    void Awake()
    {
        _instance = this;
    }

    void Start()
    {
        List<UILevel> levelInfo = UILevel.TryGet();
        for (int i = 0; i < levelInfo.Count; i++)
        {
            Transform obj = CreateLevel(string.Format("{0} - {1} -{2}", levelInfo[i].UILevelID,levelInfo[i].UILevelName,levelInfo[i].UILevelDepth));
            uiLevel.Add(levelInfo[i].UILevelID,obj);
        }

        StartCoroutine(DetectionUI());
        if (LoadPanel == null)
        {
            LoadPanel = (LoadingPanel)GetUIBase(UIType.LoadingPanel);
            LoadPanel.CloseLoading();
        }

        OpenUI( UIType.LoginPanel);
        //OpenUI( UIType.MainPanel);
        //OpenTips(UIType.TopPanel);
        //MusicControl.Instance.PlayBackMusic("LoginAudio");
    }

    /// <summary>
    /// UI銷燬計時器
    /// </summary>
    /// <returns></returns>
    IEnumerator DetectionUI()
    {
        yield return new WaitForSeconds(360);
        if (uiCache.Count > 0)
        {
            List<UIBase> bases = new List<UIBase>(uiCache.Values);
            for (int i = 0; i < bases.Count; i++)
            {
                if (!bases[i].UIConfig.UIisDestroy) continue;
                System.TimeSpan ts = System.DateTime.Now - bases[i].GetOpenTime;
                if (ts.TotalMinutes >= bases[i].UIConfig.UILife)
                {
                    Destroy(bases[i].gameObject);
                    uiCache.Remove(bases[i].UIType);
                }
            }
        }
    }

    /// <summary>
    /// 清楚UI
    /// </summary>
    /// <param name="type"></param>
    public void ClearScene(SceneType type)
    {
        List<UIBase> bases = new List<UIBase>(uiCache.Values);
        for (int i = 0; i < bases.Count; i++)
        {
            if (bases[i].UIConfig.UIType.Equals(type.ToString()))
            {
                Destroy(bases[i].gameObject);
                uiCache.Remove(bases[i].UIType);
            }
        }
    }

    /// <summary>
    /// 開啟UI
    /// </summary>
    /// <param name="uiType"></param>
    /// <param name="data"></param>
    public void OpenUI(UIType uiType,params object[] data)
    {
        if (uiCache.ContainsKey(uiType))
        {
            if(CurUiBase!=null)
                CurUiBase.OnCloseAni();
            uiCache[uiType].OpenUI(CurUiBase, data);
            CurUiBase = uiCache[uiType];
            return;
        }
        UIBase uiBase = GetUIBase(uiType);
        if (uiBase == null) return;
        if (CurUiBase != null)
            CurUiBase.OnCloseAni();
        uiBase.OnInit();
        uiBase.OpenUI(CurUiBase, data);
        CurUiBase = uiBase;
    }

    /// <summary>
    /// 開啟上一層UI
    /// </summary>
    /// <param name="uiBase"></param>
    /// <param name="data"></param>
    public void OpenPreUI(UIBase uiBase, params object[] data)
    {
        if (CurUiBase != null)
            CurUiBase.OnCloseAni();
        uiBase.OpenUI();
        CurUiBase = uiBase;
    }

    /// <summary>
    /// 開啟tips
    /// </summary>
    /// <param name="uiType"></param>
    /// <param name="data"></param>
    public void OpenTips(UIType uiType, params object[] data)
    {
        if (uiCache.ContainsKey(uiType))
        {
            uiCache[uiType].OpenUI(CurUiBase, data);
            return;
        }
        UIBase uiBase = GetUIBase(uiType);
        if (uiBase == null) return;
        uiBase.OnInit();
        uiBase.OpenUI(CurUiBase, data);
    }

    /// <summary>
    /// 更新UI
    /// </summary>
    /// <param name="uiType"></param>
    /// <param name="data"></param>
    public void UpdateUI(UIType uiType, params object[] data)
    {
        UIBase uiBase = GetUI(uiType);
        if (uiBase != null)
            uiBase.OnUpdate(data);
    }


    /// <summary>
    /// 獲取標籤
    /// </summary>
    /// <param name="uiType"></param>
    /// <returns></returns>
    public UIBase GetUI(UIType uiType, UIFilter filter = UIFilter.Open)
    {
        switch (filter)
        {
            case UIFilter.Open:
                if (uiCache.ContainsKey(uiType) && uiCache[uiType].IsOpen)
                    return uiCache[uiType];
                break;
            case UIFilter.Close:
                if (uiCache.ContainsKey(uiType) && !uiCache[uiType].IsOpen)
                    return uiCache[uiType];
                break;
            case UIFilter.All:
                if (uiCache.ContainsKey(uiType))
                    return uiCache[uiType];
                break;
        }
        return null;
    }

    /// <summary>
    /// 獲取UI
    /// </summary>
    /// <param name="uiType"></param>
    /// <returns></returns>
    private UIBase GetUIBase(UIType uiType)
    {
        UIConfig config = UIConfig.TryGet(((int)uiType).ToString());
        if (config == null)
        {
            Debug.Log(string.Format("獲取ui:{0}-{1} 資料失敗", uiType.ToString(), (int)uiType));
            return null;
        }
        GameObject uiObj = GameObject.Instantiate(Resources.Load(config.UIPath + config.UIName)) as GameObject;
        if (uiObj == null)
        {
            Debug.Log(string.Format("獲取ui:{0}-{1} 模型失敗", uiType.ToString(), (int)uiType));
            return null;
        }

        uiObj.transform.parent = uiLevel[config.UILevel];
        uiObj.transform.localPosition = Vector3.zero;
        uiObj.transform.localScale = Vector3.one;
        uiObj.transform.localEulerAngles = Vector3.zero;
        //如果鎖定UI層級
        if(!config.UILockDepth)
            ChangePanel(config.UILevel,uiObj.transform);
        UIBase uiBase = uiObj.GetComponent<UIBase>();
        uiBase.UIConfig = config;
        uiBase.UIType = uiType;
        uiCache.Add(uiType, uiBase);
        return uiBase;
    }

    /// <summary>
    /// 關閉UI
    /// </summary>
    /// <param name="uiType"></param>
    public void CloseUI(UIType uiType)
    {
        if (uiCache.ContainsKey(uiType))
            uiCache[uiType].OnCloseAni();
    }

    /// <summary>
    /// 關閉所有UI
    /// </summary>
    public void CloseAll()
    {
        List<UIBase> bs = new List<UIBase>(uiCache.Values);
        for (int i = 0; i < bs.Count; i++)
        {
            if (bs[i].IsOpen)
                bs[i].OnCloseAni();
        }
    }
    /// <summary>
    /// 過濾關閉所有
    /// </summary>
    /// <param name="filter"></param>
    public void CloseAll(UIType filter)
    {
        List<UIBase> bs = new List<UIBase>(uiCache.Values);
        for (int i = 0; i < bs.Count; i++)
        {
            if (bs[i].IsOpen&&bs[i].UIType!=filter)
                bs[i].OnCloseAni();
        }
    }


    /// <summary>
    /// 建立層級
    /// </summary>
    /// <param name="name"></param>
    /// <returns></returns>
    private Transform CreateLevel(string name)
    {
        GameObject go = new GameObject(name);
        go.transform.parent = this.transform;
        go.transform.localPosition = Vector3.zero;
        go.transform.localScale = Vector3.one;
        go.transform.localEulerAngles = Vector3.zero;
        return go.transform;
    }

    private void ChangePanel(int level,Transform obj)
    {
        //如果鎖定層級深度則跳過
        UILevel levelInfo = UILevel.TryGet(level.ToString());
        if (levelInfo.UILevelLock) return;
        int curMaxLevel = GetMax(levelInfo);
        UIPanel[] panels = obj.GetComponentsInChildren<UIPanel>();
        for (int i = 0; i < panels.Length; i++)
        {
            panels[i].depth = ++curMaxLevel;
        }
    }

    /// <summary>
    /// 獲取當前面板最大層級
    /// </summary>
    /// <param name="obj"></param>
    /// <returns></returns>
    private int GetMax(UILevel level)
    {
        int maxDepth = level.UILevelDepth;
        UIPanel[] panels = uiLevel[level.UILevelID].GetComponentsInChildren<UIPanel>();
        for (int i = 0; i < panels.Length; i++)
        {
            if (panels[i].depth > maxDepth)
                maxDepth = panels[i].depth;
        }
        return maxDepth;
    }
}

開啟一個UI
UIManager.Instance.OpenUI( UIType.LoginPanel);

執行後UI效果:
這裡寫圖片描述

最終:
這裡寫圖片描述

注意如果需要加入UI動畫,需要在UI類中重寫OnOpenAni()和OnCloseAni()方法,動畫結束後不要忘了呼叫OnOpen()和OnClose()方法

有關配置表解析部分可以檢視我的文章 “Unity3d txt配置表讀取” 或 自行解析
http://blog.csdn.net/qq_18192161/article/details/79220695