最近在写项目,但是模型比较慢,之前一直是硬写程序,也有用过其他人的框架,现在自己在B站上看了一些视频,也搜了一些文章,写了几天的简单框架,有一些心得,发出来,让大家看一看,有什么问题的大家多喷一下哈
核心的类有如下几个:
UIType:物体的基本属性,包含名称和地址。
public class UIType
{
public string Name { get; private set; }
public string Path { get; private set; }
public UIType(string path)
{
Path = path;
Name = path.Substring(path.LastIndexOf('/')+1) ;
}
}
BasePanel:主要用于面板类的基类,同时存储的有面板的状态信息。
public abstract class BasePanel
{
public UIType UIType { get; private set; }
public UITool UITool { get; private set; }
public PanelManager PanelManager { get; private set; }
public UIManager UIManager { get; private set; }
public BasePanel(UIType uIType)
{
UIType = uIType;
}
public void Initialize(UITool tool)
{
UITool = tool;
}
public void Initialize(PanelManager panel)
{
PanelManager = panel;
}
public void Initialize(UIManager uIManager)
{
UIManager = uIManager;
}
public virtual void OnEnter() { }
public virtual void OnPause() {
UITool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false;
}
public virtual void OnResume() {
UITool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = true;
}
public virtual void OnExit() { }
}
PanelManager:面板管理器,里面有一个栈,使用栈来存储UI。
public class PanelManager
{
private Stack<BasePanel> stackPanel;
private UIManager uIManager;
private BasePanel panel;
public PanelManager()
{
stackPanel = new Stack<BasePanel>();
uIManager = new UIManager();
}
public void Push(BasePanel nextPanel)
{
if (stackPanel.Count>0)
{
panel = stackPanel.Peek();
panel.OnPause();
}
stackPanel.Push(nextPanel);
GameObject panelGo = uIManager.GetSingleUI(nextPanel.UIType);
nextPanel.Initialize(new UITool(panelGo));
nextPanel.Initialize(this);
nextPanel.Initialize(uIManager);
nextPanel.OnEnter();
}
public void Pop()
{
if (stackPanel.Count>0)
{
stackPanel.Peek().OnExit();
stackPanel.Pop();
}
if (stackPanel.Count > 0)
stackPanel.Peek().OnResume();
}
}
UIManager:存储所有的UI信息,用字典进行存储。
public class UIManager
{
private Dictionary<UIType, GameObject> dicUI;
public UIManager()
{
dicUI = new Dictionary<UIType, GameObject>();
}
public GameObject GetSingleUI(UIType type)
{
GameObject parent = GameObject.Find("Canvas");
if (!parent)
{
Debug.LogError("Canvas不存在");
return null;
}
if (dicUI.ContainsKey(type))
return dicUI[type];
GameObject ui = GameObject.Instantiate(Resources.Load<GameObject>(type.Path),parent.transform);
ui.name = type.Name;
dicUI.Add(type, ui);
return ui;
}
public void DestroyUI(UIType type)
{
if (dicUI.ContainsKey(type))
{
GameObject.Destroy(dicUI[type]);
dicUI.Remove(type);
}
}
}
UITool:UI管理工具,用于获取物体以及相关组件
public class UITool
{
GameObject activePanel;
public UITool(GameObject panel)
{
activePanel = panel;
}
public T GetOrAddComponent<T>() where T : Component
{
if (activePanel.GetComponent<T>() == null)
activePanel.AddComponent<T>();
return activePanel.GetComponent<T>();
}
public GameObject FindChildGameObject(string name)
{
Transform[] trans = activePanel.GetComponentsInChildren<Transform>();
foreach (Transform item in trans)
{
if (item.name==name)
{
return item.gameObject;
}
}
Debug.LogError(activePanel+"里找不到名为"+name+"的子物体");
return null;
}
public T GetOrAddComponentInChildren<T>(string name)where T:Component
{
GameObject child = FindChildGameObject(name);
if (child)
{
if (child.GetComponent<T>() == null)
child.AddComponent<T>();
return child.GetComponent<T>();
}
return null;
}
}
通过以上5个核心脚本,可以搭配一个比较简单的UI框架。
使用方法:
我们可以创建一个新的脚本挂载在场景中的空物体上如下图的GameRoot,提前搭建好场景中的Canvas当作父物体。
然后GameRoot内容如下:
public class GameRoot : MonoBehaviour
{
PanelManager panelManager;
private void Awake()
{
panelManager = new PanelManager();
}
// Start is called before the first frame update
void Start()
{
panelManager.Push(new StartPanel());
}
}
当实例化之后,我们的开始面板就展示在眼前了
其他面板的按钮调用可以使用如下内容的方法:
public class StartPanel : BasePanel
{
static readonly string path = "Prefabs/Panel/StartPanel";
//这里需要放置我们自己面板预设体的路径
public StartPanel() : base(new UIType(path)) { }
public override void OnEnter()
{
UITool.GetOrAddComponentInChildren<Button>("BtnSetting").onClick.AddListener(()=> {
PanelManager.Push(new SettingPanel());
//通过点击设置按钮打开设置面板,但必须要有设置面板的脚本
});
UITool.GetOrAddComponentInChildren<Button>("BtnPlay").onClick.AddListener(()=> {
PanelManager.Push(new MainPanel());
UIManager.DestroyUI(UIType);
//通过点击开始按钮,打开主面板,同时删除当前面板。
});
}
}
其中,我们的面板开启使用PanelManager.Push(new 面板名称),前提是有该面板同时继承了basePanel并设置了路径。
按钮点击事件可以使用UITool中的GetOrAddComponentInChildren方法来进行按钮和事件的绑定:
UITool.GetOrAddComponentInChildren<Button>("BtnPlay").onClick.AddListener(()=> {
PanelManager.Push(new MainPanel());
UIManager.DestroyUI(UIType);
//通过点击开始按钮,打开主面板,同时删除当前面板。
});