整个游戏的工程源码下载链接:点击打开链接
可以参考的写的Demo和本文章来学习
毕竟有些细节问题在文章中不能一一说到
工具:VS2010、Unity5.2.3f
先介绍整个Demo的主面板
其中任务、技能、符文等等都是按钮,点击按钮会生成相应面板
【Protobuf的生成与解析】
要使得框架的可扩展性与自适应性,我把各个面板的名字与路径配置到protobuf文件
在VS中我们把代码编写完成后生成protobuf文件
在Unity中解析
如何生成与解析请参考:点击打开链接
【UIManager】
在Unity工程中,使用UIManager这个类对整个UI框架进行管理
UIManager.cs
using UnityEngine;
using System.Collections;
using UIFrameworkForProtobuf;
using System.Collections.Generic;public class UIManager
{private Dictionary<UIPanelTypeEnum, string> dicPanelPath;//存储面板路径private Dictionary<UIPanelTypeEnum, BaseManager> dicPanelBase;//存储面板BaseManager组件private Stack<BaseManager> panelStack;//单例模式private static UIManager manager;public static UIManager GetInstance{get{if (manager == null){manager = new UIManager();}return manager;}}private UIManager(){Dederializer();}private Transform canvasTransform;private Transform CanvasTransform{get{if (canvasTransform == null){canvasTransform = GameObject.Find("Canvas").transform;}return canvasTransform;}}
//面板入栈public void PushPanel(UIPanelTypeEnum panelType){if (panelStack == null){panelStack = new Stack<BaseManager>();}//判断栈里面是否有页面,如果有,将栈中top对象取出if (panelStack.Count > 0){BaseManager top = panelStack.Peek();top.OnPause();}BaseManager bm = GetPanel(panelType);panelStack.Push(bm);bm.OnEnter();}
//面板入栈public void PushPanel(UIPanelTypeEnum panelType){if (panelStack == null){panelStack = new Stack<BaseManager>();}//判断栈里面是否有页面,如果有,将栈中top对象取出if (panelStack.Count > 0){BaseManager top = panelStack.Peek();top.OnPause();}BaseManager bm = GetPanel(panelType);panelStack.Push(bm);bm.OnEnter();}
//面板出栈public void PopPanel(){if (panelStack == null){panelStack = new Stack<BaseManager>();}if (panelStack.Count <= 0){return;}//关闭栈顶的页面显示BaseManager bm = panelStack.Pop();bm.OnExit();if (panelStack.Count <= 0){return;}BaseManager top = panelStack.Peek();top.OnResume();}private BaseManager GetPanel(UIPanelTypeEnum panelType){if (dicPanelBase == null){dicPanelBase = new Dictionary<UIPanelTypeEnum, BaseManager>();}BaseManager bm;dicPanelBase.TryGetValue(panelType,out bm);if (bm == null){string panelPath;dicPanelPath.TryGetValue(panelType, out panelPath);GameObject objPanel = GameObject.Instantiate(Resources.Load(panelPath)) as GameObject;objPanel.transform.SetParent(CanvasTransform, false);//参数二:是否保留世界坐标信息,由于要将对象存放在Canvase下,所以为falsedicPanelBase.Add(panelType, objPanel.GetComponent<BaseManager>());return objPanel.GetComponent<BaseManager>();}else{return bm;}}//将protobuf文件反序列化为对象private void Dederializer(){dicPanelPath = new Dictionary<UIPanelTypeEnum, string>();UIPanelTypeList panelTypes = ProtobufHelper.DederializerFromFile<UIPanelTypeList>(Application.streamingAssetsPath + "/UIPanelType.bin");foreach (UIPanelType type in panelTypes.uiPanelTypes){UIPanelTypeEnum enumType = (UIPanelTypeEnum)System.Enum.Parse(typeof(UIPanelTypeEnum), type.panelName);dicPanelPath.Add(enumType, type.panelPath);Debug.Log(type.panelName);Debug.Log(type.panelPath);}}
}
//面板出栈public void PopPanel(){if (panelStack == null){panelStack = new Stack<BaseManager>();}if (panelStack.Count <= 0){return;}//关闭栈顶的页面显示BaseManager bm = panelStack.Pop();bm.OnExit();if (panelStack.Count <= 0){return;}BaseManager top = panelStack.Peek();top.OnResume();}private BaseManager GetPanel(UIPanelTypeEnum panelType){if (dicPanelBase == null){dicPanelBase = new Dictionary<UIPanelTypeEnum, BaseManager>();}BaseManager bm;dicPanelBase.TryGetValue(panelType,out bm);if (bm == null){string panelPath;dicPanelPath.TryGetValue(panelType, out panelPath);GameObject objPanel = GameObject.Instantiate(Resources.Load(panelPath)) as GameObject;objPanel.transform.SetParent(CanvasTransform, false);//参数二:是否保留世界坐标信息,由于要将对象存放在Canvase下,所以为falsedicPanelBase.Add(panelType, objPanel.GetComponent<BaseManager>());return objPanel.GetComponent<BaseManager>();}else{return bm;}}//将protobuf文件反序列化为对象private void Dederializer(){dicPanelPath = new Dictionary<UIPanelTypeEnum, string>();UIPanelTypeList panelTypes = ProtobufHelper.DederializerFromFile<UIPanelTypeList>(Application.streamingAssetsPath + "/UIPanelType.bin");foreach (UIPanelType type in panelTypes.uiPanelTypes){UIPanelTypeEnum enumType = (UIPanelTypeEnum)System.Enum.Parse(typeof(UIPanelTypeEnum), type.panelName);dicPanelPath.Add(enumType, type.panelPath);Debug.Log(type.panelName);Debug.Log(type.panelPath);}}
}
【面板状态组件】
我们为每个面板添加一个C#脚本组件,分别命名为TaskPanel、SkillPanel.............
他们分别继承自BaseManager类
BaseManager.cs
using UnityEngine;
using System.Collections;public class BaseManager :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(){}
}
这里介绍主面板的MainPanel组件
MainPanel.cs
using UnityEngine;
using System.Collections;public class MainPanel : BaseManager
{private CanvasGroup canvasGroup;void Start(){canvasGroup = GetComponent<CanvasGroup>();}public override void OnPause(){canvasGroup.blocksRaycasts = false;//当弹出新的面板的时候,让主菜单面板 不再和鼠标交互}public override void OnResume(){canvasGroup.blocksRaycasts = true;}public void OnPushPanel(string panelTypeString){UIPanelTypeEnum panelType = (UIPanelTypeEnum)System.Enum.Parse(typeof(UIPanelTypeEnum), panelTypeString);UIManager.GetInstance.PushPanel(panelType);}
}
主面板的各个按钮中,将按钮点击事件注册到OnPushPanel函数中,并传入一个面板名
【检测】
将主面板添加到游戏对象上
ManagerRoot.cs
using UnityEngine;
using System.Collections;public class ManagerRoot : MonoBehaviour
{// Use this for initializationvoid Start () {UIManager.GetInstance.PushPanel(UIPanelTypeEnum.Main);}}
文章写得并不是很详细和易懂得话可以下载参考我的源码