《UI框架—基于Unity5.4UGUI(二)》

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Say__Yes/article/details/74086620

接着上一篇的介绍,这一篇就该干点实事了—上代码。但是在这之前,我先给出UI框架在Unity中的资源文件的截图,方便大家理解(其中的预制体和代码是根据上一篇博客的讲解给出):
这里写图片描述

1.存储面板类型和面板预设路径的Json文本如下:

{
"infoList":
[
{"panelTypeString":"ItemMessage",
"path":"UIPanel/ItemMessagePanel"},

{"panelTypeString":"Knapsack",
"path":"UIPanel/KnapsackPanel"},

{"panelTypeString":"MainMenu",
"path":"UIPanel/MainMenuPanel"},

{"panelTypeString":"Shop",
"path":"UIPanel/ShopPanel"},

{"panelTypeString":"Skill",
"path":"UIPanel/SkillPanel"},

{"panelTypeString":"System",
"path":"UIPanel/SystemPanel"},

{"panelTypeString":"Task",
"path":"UIPanel/TaskPanel"}

]
}

2.每个面板对应的枚举如下:

using UnityEngine;
using System.Collections;

public enum UIPanelType
{
    MainMenu,
    Knapsack,
    Shop,
    Skill,
    Task,
    System,
    ItemMessage
}

3.每个UI界面信息对应的类(也就是解析出来的Json对应的类):

using UnityEngine;
using System.Collections;
using System;

[Serializable]
public class UIPanelInfo : ISerializationCallbackReceiver{//和json文件信息对应的一个类
    //不可序列化的,因为这里unity解析json文件时没办法解析枚举类型,所以下面定义了一个string类型的字段panelTypeString,用于两者的转化
    [NonSerialized]
    public UIPanelType panelType;//面板类型
    public string panelTypeString;
    public  string path;//面板所在路径

    //实现ISerializationCallbackReceiver的接口, 反序列化方法,从文本信息到对象
    public void OnAfterDeserialize()
    {
        UIPanelType type = (UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);//把一个字符串转化为一个枚举
        panelType = type;
    }

    //实现接口, 序列化方法,从对象到文本信息
    public void OnBeforeSerialize(){}
}

4.(重点)UIManager管理各个UI面板的核心类:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// 单例模式的核心:
/// 1.只在该类内定义一个静态的对象,该对象在外界访问,在内部构造
/// 2.构造函数私有化
/// </summary>
public class UIManager{//此类作为一个单例模式,即只有一个实例的模式

    private static UIManager _instance;
    public static UIManager Instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = new UIManager();
            }
            return _instance;
        }
    }

    private UIManager() //构造函数私有化(单例模式)
    {
        ParseUIPanelTypeJson();//构造该类时会解析Json
    }

    private Dictionary<UIPanelType, string> panelPathDict;//存储所有Perfab面板的路径
    private Dictionary<UIPanelType, BasePanel> panelDict;//借助BasePanel脚本保存所有实例化出来的面板物体(因为BasePanel脚本被所有面板预设物体的自己的脚本所继承,所以需要的时候可以根据BasePanel脚本来实例化每一个面板对象)
    private Stack<BasePanel> panelStack;//这是一个栈,用来保存实例化出来(显示出来)的面板

    private Transform canvasTransform;//用来使实例化的面板归为它的子物体
    private Transform CanvasTransform 
    {
        get {
            if (canvasTransform == null)
            {
                canvasTransform = GameObject.Find("Canvas").transform;
            }
            return canvasTransform;
        }
    }

    //页面入栈,即把页面显示在界面上
    public void PushPanel(UIPanelType panelType)
    {
        if (panelStack == null)//如果栈不存在,就实例化一个空栈
        {
            panelStack = new Stack<BasePanel>();
        }
        if (panelStack.Count > 0)
        {
            BasePanel topPanel = panelStack.Peek();//取出栈顶元素保存起来,但是不移除
            topPanel.OnPause();//使该页面暂停,不可交互
        }
        BasePanel panelTemp = GetPanel(panelType);
        panelTemp.OnEnter();//页面进入显示,可交互
        panelStack.Push(panelTemp);
    }
    //页面出栈,即把页面从界面上移除
    public void PopPanel() 
    {
        if (panelStack == null)
        {
            panelStack = new Stack<BasePanel>();
        }
        if (panelStack.Count <= 0)  return;
        //关闭栈顶页面的显示
        BasePanel topPanel1 = panelStack.Pop();
        topPanel1.OnExit();
        if (panelStack.Count <= 0) return;
        BasePanel topPanel2 = panelStack.Peek();
        topPanel2.OnResume();//使第二个栈里的页面显示出来,并且可交互
    }

    [System.Serializable]
    class UIPanelTypeJson //内部类里面就一个链表容器,用来配合解析
    {
        public List<UIPanelInfo> infoList;
    }

    //根据面板类型UIPanelType得到实例化的面板
    private BasePanel GetPanel(UIPanelType panelType) 
    {
        if (panelDict == null)//如果panelDict字典为空,就实例化一个空字典
        {
            panelDict = new Dictionary<UIPanelType, BasePanel>();
        }
        //BasePanel panel;
        //panelDict.TryGetValue(panelType, out panel);//不为空就根据类型得到Basepanel
        BasePanel panel = panelDict.TayGet(panelType);//我们扩展的Dictionary的方法,代码作用同上两行
        if (panel == null)//如果得到的panel为空,那就去panelPathDict字典里面根据路径path找到,然后加载,接着实例化
        {
            string path = panelPathDict.TayGet(panelType);//我们扩展的Dictionary的方法
            //panelPathDict.TryGetValue(panelType, out path);
            GameObject instPanel = GameObject.Instantiate(Resources.Load(path)) as GameObject;//根据路径加载并实例化面板
            instPanel.transform.SetParent(this.CanvasTransform,false);//设置为Canvas的子物体,false表示实例化的子物体坐标以Canvas为准
            //TODO
            panelDict.Add(panelType,instPanel.GetComponent<BasePanel>());
            return instPanel.GetComponent<BasePanel>();
        }
        else
        {
            return panel;
        }

    }

    //解析UIPanelType.json的信息
    private void ParseUIPanelTypeJson()
    {
        panelPathDict = new Dictionary<UIPanelType, string>();//实例化一个字典对象
        TextAsset ta = Resources.Load<TextAsset>("UIPanelType"); //获取UIPanelType.json文件的文本信息
        UIPanelTypeJson jsonObject = JsonUtility.FromJson<UIPanelTypeJson>(ta.text);//把UIPanel.json文本信息转化为一个内部类的对象,对象里面的链表里面对应的是每个Json信息对应的类
        foreach (UIPanelInfo info in jsonObject.infoList)
        {
            //Debug.Log(info.panelType);
            panelPathDict.Add(info.panelType, info.path);//把每一个进过json文件转化过来的类存入字典里面(键值对的形式)
        }
    }
}

5.启动整个UI框架的类(这里只需要再启动游戏时加载主界面就好,其他界面是需要点击按钮时才会实例出来并显示):

using UnityEngine;
using System.Collections;

public class GameRoot : MonoBehaviour
{
    // Use this for initialization
    void Start () {
        UIManager.Instance.PushPanel(UIPanelType.MainMenu);
    }
}

6.BasePanel各个面板的基类(定义各个面板共有的四个状态):

using UnityEngine;
using System.Collections;

//所有面板的公共基类
public class BasePanel : MonoBehaviour {
    /// <summary>
    /// 页面进入显示,可交互
    /// </summary>
    public virtual void OnEnter(){}

    /// <summary>
    /// 页面暂停(弹出了其他页面),不可交互
    /// </summary>
    public virtual void OnPause(){}

    /// <summary>
    /// 页面继续显示(其他页面关闭),可交互
    /// </summary>
    public virtual void OnResume(){}

    /// <summary>
    /// 本页面被关闭(移除),不再显示在界面上
    /// </summary>
    public virtual void OnExit(){}
}

7.主界面:

using UnityEngine;
using System.Collections;

public class MainMenuPanel : BasePanel{

    private CanvasGroup canvasGroup;//获取CanvasGroup组件,用于控制该面板的交互功能

    void Start() 
    {
        canvasGroup = this.GetComponent<CanvasGroup>();
    }

    public override void OnPause()//重写父类BasePanel的OnPause方法
    {
        canvasGroup.blocksRaycasts = false;//使该面板失去交互功能
    }
    //重写父类BasePanel的OnResume方法
    public override void OnResume()
    {
        canvasGroup.blocksRaycasts = true;//使该面板继续交互功能
    }


    //点击功能模块按钮加载面板,并将其入栈
    public void OnPushPanel(string panelTypeString) 
    {
        //把一个字符串转化为对应的枚举类型
        UIPanelType panelType =(UIPanelType)System.Enum.Parse(typeof(UIPanelType), panelTypeString);
        UIManager.Instance.PushPanel(panelType);
    }

}

8.任务面板:

using UnityEngine;
using System.Collections;
using DG.Tweening;

public class TaskPanel : BasePanel {

    private CanvasGroup canvasGroup;//对该页面CanvasGroup组件的引用

    void Start() {
        if(canvasGroup == null) canvasGroup = this.GetComponent<CanvasGroup>();
    }
    //重写父类的OnEnter方法
    public override void OnEnter()
    {
        if (canvasGroup == null) canvasGroup = this.GetComponent<CanvasGroup>();
        this.canvasGroup.alpha = 0;
        this.canvasGroup.blocksRaycasts = true;//使该页面可交互
        canvasGroup.DOFade(1, 0.6f);//使该页面渐渐显示,1是Alpha值
    }
    //重写父类的OnExit方法
    public override void OnExit()
    {
        this.canvasGroup.blocksRaycasts = false;//使该页面不可交互
        canvasGroup.DOFade(0, 0.6f);//使该页面渐渐隐藏,0是Alpha值
    }

    //点击关闭按钮事件
    public void OnClose() 
    {
        UIManager.Instance.PopPanel();
    }

}

9.背包面板:

using UnityEngine;
using System.Collections;
using DG.Tweening;

public class KnapsackPanel : BasePanel {
    private CanvasGroup canvasGroup;

    void Awake() 
    {
        this.canvasGroup = this.GetComponent<CanvasGroup>();
    }

    public override void OnEnter()
    {
        this.canvasGroup.alpha = 1;
        this.canvasGroup.blocksRaycasts = true;
        Vector3 temp = this.transform.localPosition;
        temp.x = 600;
        this.transform.localPosition = temp;
        this.transform.DOLocalMoveX(0, 0.6f);
    }
    public override void OnExit()
    {
        //this.canvasGroup.alpha = 0;
        this.canvasGroup.blocksRaycasts = false;
        this.transform.DOLocalMoveX(-600, 0.6f).OnComplete(()=>canvasGroup.alpha =0);
    }

    public override void OnPause()
    {
        this.canvasGroup.blocksRaycasts = false;
    }

    public override void OnResume()
    {
        this.canvasGroup.blocksRaycasts = true;
    }
    //点击关闭按钮
    public void OnClose() 
    {
        UIManager.Instance.PopPanel();
    }

    //点击装备,显示装备信息
    public void OnItemButtonDown() 
    {
        UIManager.Instance.PushPanel(UIPanelType.ItemMessage);
    }
}

10.技能面板

using UnityEngine;
using System.Collections;

public class SkillPanel : BasePanel {
    private CanvasGroup canvasGroup;

    void Awake()
    {
        this.canvasGroup = this.GetComponent<CanvasGroup>();
    }

    public override void OnEnter()
    {
        this.canvasGroup.alpha = 1;
        this.canvasGroup.blocksRaycasts = true;
    }
    public override void OnExit()
    {
        this.canvasGroup.alpha = 0;
        this.canvasGroup.blocksRaycasts = false;
    }

    public void OnClose()
    {
        UIManager.Instance.PopPanel();
    }
}

11.商城面板:

using UnityEngine;
using System.Collections;

public class ShopPanel : BasePanel {
    private CanvasGroup canvasGroup;

    void Awake()
    {
        this.canvasGroup = this.GetComponent<CanvasGroup>();
    }

    public override void OnEnter()
    {
        this.canvasGroup.alpha = 1;
        this.canvasGroup.blocksRaycasts = true;
    }
    public override void OnExit()
    {
        this.canvasGroup.alpha = 0;
        this.canvasGroup.blocksRaycasts = false;
    }

    public void OnClose()
    {
        UIManager.Instance.PopPanel();
    }
}

12.系统设置面板:

using UnityEngine;
using System.Collections;

public class SystemPanel : BasePanel {
    private CanvasGroup canvasGroup;

    void Awake()
    {
        this.canvasGroup = this.GetComponent<CanvasGroup>();
    }

    public override void OnEnter()
    {
        this.canvasGroup.alpha = 1;
        this.canvasGroup.blocksRaycasts = true;
    }
    public override void OnExit()
    {
        this.canvasGroup.alpha = 0;
        this.canvasGroup.blocksRaycasts = false;
    }

    public void OnClose()
    {
        UIManager.Instance.PopPanel();
    }
}

13.背包里的装备信息提示面板:

using UnityEngine;
using System.Collections;
using DG.Tweening;

public class ItemMessagePanel : BasePanel{
    private CanvasGroup canvasGroup;

    void Awake()
    {
        this.canvasGroup = this.GetComponent<CanvasGroup>();
    }

    public override void OnEnter()
    {
        this.canvasGroup.alpha = 1;
        this.canvasGroup.blocksRaycasts = true;
        this.transform.localScale = Vector3.zero;
        transform.DOScale(1, 0.6f);//缩放动画,1代表结束时的缩放
    }
    public override void OnExit()
    {
        //this.canvasGroup.alpha = 0;
        this.canvasGroup.blocksRaycasts = false;
        transform.DOScale(0, 0.6f).OnComplete(() => canvasGroup.alpha = 0);
    }

    public void OnClose()
    {
        UIManager.Instance.PopPanel();
    }
}

14.字典拓展类(用于拓展Dictionary类的TryGetValue( )方法,只是为了简化代码方便使用,UI框架里可有可无):

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

//对字典类的TayGetValue( )方法的扩展
/// <summary>
/// 尝试根据key得到value,得到返回value,否则返回null
/// this Dictionary<Tkey,Tvalue> dict   这个字典表示我们要获取值value的字典
/// 扩展方法规定类必须是一个静态类.里面包含的所有方法都必须是静态方法。扩展方法被定义为静态方法,但它们是通过实例方法语法进行调用的。 它们的第一个参数指定该方法作用于哪个类型,并且该参数以 this 修饰符为前缀。
/// </summary>
public static class DictionaryExtension {
    public static Tvalue TayGet<Tkey,Tvalue>( this Dictionary<Tkey,Tvalue> dict,Tkey key)
    {
        Tvalue value;
        dict.TryGetValue(key,out value);
        return value;
    }
}

总结:该UI框架重点在于UI核心管理类(UIManager)的实现,其中使用栈先进后出,后进先出的思想实现了页面的逻辑管理。难点呢在于实现Json文本的解析。

猜你喜欢

转载自blog.csdn.net/Say__Yes/article/details/74086620
今日推荐