此博客跟随siki老师的课程笔记生成,感谢siki老师的辛勤付出!
此框架功能较简单,适用于学习,可以很好的锻炼我们的设计思想
框架源码地址: UIFramework
litjson.dll下载地址: litjson
1.随着游戏系统的复杂,UI控件越来越多,各个UI直接的通讯,以及UI与GameObject之间的通讯形成一张复杂的蜘蛛网,
拖着拖着,有时候我都忘了哪个对象跟哪个对象关联了。如果是别人要看我的程序,我估计他找半天都找不到UI逻辑的入口。
2.耦合性非常严重,如果要改变需求,更改某个UI或者更改某个游戏对象,那么你需要再手动全部与该对象关联的物件重新更改一次。
3.作为强迫症的程序员,最受不了程序代码的混乱。这种组织方式十分“不优雅”,看着很乱。
鉴于以上各种情况,我们需要寻找一种新的,科学的,高效的UI管理方式
将面板以Prefab形式放入Resources文件夹下面,便于框架加载面板
UIPanelType.json:
{
"panelInfoList":
[
{"panelType":"MainMenu","path":"UIPanel/MainMenuPanel"},
{"panelType":"ItemMessage","path":"UIPanel/ItemMessagePanel"},
{"panelType":"Knapsack","path":"UIPanel/KnapsackPanel"},
{"panelType":"Shop","path":"UIPanel/ShopPanel"},
{"panelType":"Skill","path":"UIPanel/SkillPanel"},
{"panelType":"System","path":"UIPanel/SystemPanel"},
{"panelType":"Task","path":"UIPanel/TaskPanel"}
]
}
UIPanelType.cs:
public class UIPanelType {
public const string MainMenu = "MainMenu";
public const string Knapsack = "Knapsack";
public const string ItemMessage = "ItemMessage";
public const string Shop = "Shop";
public const string Skill = "Skill";
public const string System = "System";
public const string Task = "Task";
}
UIManager为框架的核心,全局只有一个UIManager,因此UIManager要使用单例模式
现阶段的完整的UIManager.cs(后续还会继续完善):
using System.Collections.Generic;
using System.Collections;
using System;
using UnityEngine;
using LitJson;
public class UIPanelManager
{
private static UIPanelManager _instance;
public static UIPanelManager Instance
{
get
{
if (_instance == null)
{
_instance = new UIPanelManager();
}
return _instance;
}
}
private Dictionary<string, string> panelPathDict;
//private Dictionary
//private Stack<>
private UIPanelManager()
{
ParseUIPanelTypeJson();
}
private void ParseUIPanelTypeJson()
{
panelPathDict = new Dictionary<string, string>();
TextAsset textUIPanelType = Resources.Load("UIPanelTypeJson");
UIPanelInfoList panelInfoList = JsonMapper.ToObject(textUIPanelType.text);
foreach (UIPanelInfo panelInfo in panelInfoList.panelInfoList)
{
panelPathDict.Add(panelInfo.panelType, panelInfo.path);
Debug.Log(panelInfo.panelType + ":" + panelInfo.path);
}
}
}
BasePanel给每个Panel定义了四个事件:
OnEnter:面板进入时调用
OnPause:面板停止时调用(鼠标与面板的交互停止)
OnResume:面板恢复使用时调用(鼠标与面板的交互恢复)
OnExit:面板退出时调用
using UnityEngine;
public abstract class BasePanel : MonoBehaviour
{
public abstract void OnEnter();
public abstract void OnPause();
public abstract void OnResume();
public abstract void OnExit();
}
using UnityEngine;
public class MainMenuPanel : BasePanel
{
public override void OnEnter()
{
}
public override void OnPause()
{
}
public override void OnResume()
{
}
public override void OnExit()
{
}
}
获取Panel(如果panel没有被实例化,进行实例化,并且存储到已经实例化好的panel字典中)
private BasePanel GetPanel(string panelType)
{
BasePanel panel = panelDict.GetValue(panelType);
//如果没有实例化面板,寻找路径进行实例化,并且存储到已经实例化好的字典面板中
if (panel == null)
{
string path = panelPathDict.GetValue(panelType);
Transform panelTransform = GameObject.Instantiate(Resources.Load(path), canvasTransform).transform;
panel = panelTransform.GetComponent();
panelDict.Add(panelType, panel);
}
return panel;
}
字典的扩展:
using System.Collections.Generic;
public static class DictTool
{
public static Tvalue GetValue(this Dictionary dict, Tkey key)
{
Tvalue value = default(Tvalue);
dict.TryGetValue(key, out value);
return value;
}
}
现阶段的完整的UIManager.cs(后续还会继续完善):
using System.Collections.Generic;
using System.Collections;
using System;
using UnityEngine;
using LitJson;
public class UIPanelManager
{
private static UIPanelManager _instance;
private Transform canvasTransform;
private Transform CanvasTransform
{
get
{
if (canvasTransform == null)
{
canvasTransform = GameObject.Find("Canvas").transform;
}
return canvasTransform;
}
}
public static UIPanelManager Instance
{
get
{
if (_instance == null)
{
_instance = new UIPanelManager();
}
return _instance;
}
}
private Dictionary<string, string> panelPathDict;
private Dictionary<string, BasePanel> panelDict;
//private Stack<>
private UIPanelManager()
{
ParseUIPanelTypeJson();
}
private BasePanel GetPanel(string panelType)
{
if (panelDict == null)
{
panelDict = new Dictionary<string, BasePanel>();
}
BasePanel panel = panelDict.GetValue(panelType);
//如果没有实例化面板,寻找路径进行实例化,并且存储到已经实例化好的字典面板中
if (panel == null)
{
string path = panelPathDict.GetValue(panelType);
GameObject panelGo = GameObject.Instantiate(Resources.Load(path), CanvasTransform, false);
panel = panelGo.GetComponent();
panelDict.Add(panelType, panel);
}
return panel;
}
//解析json文件
private void ParseUIPanelTypeJson()
{
panelPathDict = new Dictionary<string, string>();
TextAsset textUIPanelType = Resources.Load("UIPanelTypeJson");
UIPanelInfoList panelInfoList = JsonMapper.ToObject(textUIPanelType.text);
foreach (UIPanelInfo panelInfo in panelInfoList.panelInfoList)
{
panelPathDict.Add(panelInfo.panelType, panelInfo.path);
//Debug.Log(panelInfo.panelType + ":" + panelInfo.path);
}
}
}
【设计理念】
1.鼠标只允许和一个界面进行交互,当一个界面显示后,上一个界面要停止和鼠标的交互
2.界面显示,进行入栈操作(Push,OnEnter),停止上一个界面(OnPause)
3.界面隐藏,进行出栈操作(Pop,OnExit),恢复上一个界面(OnResume)
private Stack panelStack;
public void PushPanel(string panelType)
{
if (panelStack == null)
{
panelStack = new Stack();
}
//停止上一个界面
if (panelStack.Count > 0)
{
BasePanel topPanel = panelStack.Peek();
topPanel.OnPause();
}
BasePanel panel = GetPanel(panelType);
panelStack.Push(panel);
panel.OnEnter();
}
public void PopPanel()
{
if (panelStack == null)
{
panelStack = new Stack();
}
if (panelStack.Count <= 0)
{
return;
}
//退出栈顶面板
BasePanel topPanel = panelStack.Pop();
topPanel.OnExit();
//恢复上一个面板
if (panelStack.Count > 0)
{
BasePanel panel = panelStack.Peek();
panel.OnResume();
}
}
完善面板中的一些操作,实现面板之间的跳转,此部分不是框架部分,省略!
MainMenuPanel.cs:
using UnityEngine;
using UnityEngine.UI;
public class MainMenuPanel : BasePanel
{
private Button TaskButton;
private Button KnapsackButton;
private Button SkillButton;
private Button ShopButton;
private Button SystemButton;
private CanvasGroup canvasGroup;
void Awake()
{
TaskButton = transform.Find("IconPanel/TaskButton").GetComponent
【BasePanel(基类):所有面板继承自BasePanel】
定义了四个事件:
OnEnter:面板进入时调用
OnPause:面板停止时调用(鼠标与面板的交互停止)
OnResume:面板恢复使用时调用(鼠标与面板的交互恢复)
OnExit:面板退出时调用
using UnityEngine;
public abstract class BasePanel : MonoBehaviour
{
public abstract void OnEnter();
public abstract void OnPause();
public abstract void OnResume();
public abstract void OnExit();
}
【GameRoot】
实例化游戏中的主面板
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
public class GameRoot : MonoBehaviour {
void Start () {
UIPanelManager panelManager = UIPanelManager.Instance;
panelManager.PushPanel(UIPanelType.MainMenu);
}
}
【UIPanelManager(框架的核心,单例)】
进行解析面板信息json文件,实例化面板Prefab,面板的入栈和出栈等等一系列操作
using System.Collections.Generic;
using System.Collections;
using System;
using UnityEngine;
using LitJson;
public class UIPanelManager
{
private static UIPanelManager _instance;
private Transform canvasTransform;
private Transform CanvasTransform
{
get
{
if (canvasTransform == null)
{
canvasTransform = GameObject.Find("Canvas").transform;
}
return canvasTransform;
}
}
public static UIPanelManager Instance
{
get
{
if (_instance == null)
{
_instance = new UIPanelManager();
}
return _instance;
}
}
private Dictionary<string, string> panelPathDict;
private Dictionary<string, BasePanel> panelDict;
private Stack panelStack;
private UIPanelManager()
{
ParseUIPanelTypeJson();
}
public void PushPanel(string panelType)
{
if (panelStack == null)
{
panelStack = new Stack();
}
//停止上一个界面
if (panelStack.Count > 0)
{
BasePanel topPanel = panelStack.Peek();
topPanel.OnPause();
}
BasePanel panel = GetPanel(panelType);
panelStack.Push(panel);
panel.OnEnter();
}
public void PopPanel()
{
if (panelStack == null)
{
panelStack = new Stack();
}
if (panelStack.Count <= 0)
{
return;
}
//退出栈顶面板
BasePanel topPanel = panelStack.Pop();
topPanel.OnExit();
//恢复上一个面板
if (panelStack.Count > 0)
{
BasePanel panel = panelStack.Peek();
panel.OnResume();
}
}
private BasePanel GetPanel(string panelType)
{
if (panelDict == null)
{
panelDict = new Dictionary<string, BasePanel>();
}
BasePanel panel = panelDict.GetValue(panelType);
//如果没有实例化面板,寻找路径进行实例化,并且存储到已经实例化好的字典面板中
if (panel == null)
{
string path = panelPathDict.GetValue(panelType);
GameObject panelGo = GameObject.Instantiate(Resources.Load(path), CanvasTransform, false);
panel = panelGo.GetComponent();
panelDict.Add(panelType, panel);
}
return panel;
}
//解析json文件
private void ParseUIPanelTypeJson()
{
panelPathDict = new Dictionary<string, string>();
TextAsset textUIPanelType = Resources.Load("UIPanelTypeJson");
UIPanelInfoList panelInfoList = JsonMapper.ToObject(textUIPanelType.text);
foreach (UIPanelInfo panelInfo in panelInfoList.panelInfoList)
{
panelPathDict.Add(panelInfo.panelType, panelInfo.path);
//Debug.Log(panelInfo.panelType + ":" + panelInfo.path);
}
}
}
【litjson】
json文件解析的工具
【UIPanelTypeJson(保存面板信息的json文件)】
1.此文件需要加载,保存到Resources文件下
2.保存了面板的类型(相当于名称)和面板Prefab的路径(实例化面板时要用到)
3.每添加一个面板,都要在此文件添加该面板对应的信息
{
"panelInfoList":
[
{"panelType":"MainMenu","path":"UIPanel/MainMenuPanel"},
{"panelType":"ItemMessage","path":"UIPanel/ItemMessagePanel"},
{"panelType":"Knapsack","path":"UIPanel/KnapsackPanel"},
{"panelType":"Shop","path":"UIPanel/ShopPanel"},
{"panelType":"Skill","path":"UIPanel/SkillPanel"},
{"panelType":"System","path":"UIPanel/SystemPanel"},
{"panelType":"Task","path":"UIPanel/TaskPanel"}
]
}
【DictTool】
Dictionnary的拓展工具类
using System.Collections.Generic;
public static class DictTool
{
public static Tvalue GetValue(this Dictionary dict, Tkey key)
{
Tvalue value = default(Tvalue);
dict.TryGetValue(key, out value);
return value;
}
}
【UIPanelInfo(面板的信息类)】
包括面板的名称和面板Prefab的路径
用于和json文件进行映射
using System;
[Serializable]
public class UIPanelInfo
{
public string panelType;
public string path;
public UIPanelInfo()
{
}
}
【UIPanelInfoList(面板信息集合类)】
用于和json文件进行映射
using System;
using System.Collections.Generic;
[Serializable]
public class UIPanelInfoList
{
public List panelInfoList;
public UIPanelInfoList() { }
}
【UIPanelType(面板的类型)】
用来记录面板的类型(名称)
每添加一个面板都要在此类里面添加对应面板的类型
public class UIPanelType {
public const string MainMenu = "MainMenu";
public const string Knapsack = "Knapsack";
public const string ItemMessage = "ItemMessage";
public const string Shop = "Shop";
public const string Skill = "Skill";
public const string System = "System";
public const string Task = "Task";
}
(完)