Unity基础UI框架
更新
在之前做項目的學習到要讓UI生成在我們制作成預制體之前的位置(一般情況下都是這樣)
需要把對象池里面的生成函數變成這樣
生成函數改成這樣
GameObject curPanel = PoolManager.GetInstance().GetObject(GetPanelString(panelType), CanvasTransform.position, false);其他不需要做任何修改
目的
這只是針對大家做一些小游戲的時候可能用到的UI框架,主要目的在于:
設計
UI的獲取和放回使用對象池實現,
實現
對象池
用于得到不同面板的預制體,遇事不決對象池
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 對象池管理器,可以調用其中的函數獲取對象 /// list存儲游戲物體,Dictionary制作抽屜 /// </summary> public class PoolManager : BaseManager<PoolManager> {public Dictionary<string, List<GameObject>> poolDic = new Dictionary<string, List<GameObject>>();/// <summary>/// 從池子里面取得物品/// </summary>/// <param name="name"></param>/// <returns></returns>public GameObject GetObject(string name, Vector3 location) {GameObject obj = null;if(poolDic.ContainsKey(name) && poolDic[name].Count > 0){//Debug.Log("Find item" + name);obj = poolDic[name][0];obj.transform.position = location;poolDic[name].RemoveAt(0);}else{obj = GameObject.Instantiate(Resources.Load<GameObject>(name), location, Quaternion.identity);//Debug.Log(name);}obj.SetActive(true);return obj;}public void PushObj(string name, GameObject obj){obj.SetActive(false);//已經擁有抽屜if(poolDic.ContainsKey(name)){poolDic[name].Add(obj);}//里面沒有抽屜else{poolDic.Add(name, new List<GameObject>() { obj });}}/// <summary>/// 場景切換時調用/// </summary>public void Clear(){poolDic.Clear();} }單例基類
繼承的類就能開單例
public class BaseManager<T> where T : new() {private static T instance;public static T GetInstance(){if (instance == null){instance = new T();return instance;}else{return instance;}} }BasePanel
BasePanel,作為不同類型Panel的抽象基類,提供三個方法接口,繼承Mono,其子類可以直接掛載在物體上。作用如注釋。
using System.Collections; using System.Collections.Generic;public abstract class BasePanel:MonoBehaviour {/// <summary>/// 開啟面板的時候調用/// </summary>public abstract void OnEnter();/// <summary>/// 當前面板在棧中而不是在棧頂的時候調用/// </summary>public abstract void OnPause();/// <summary>/// 當前面板再次處于棧頂的時候調用/// </summary>public abstract void OnResume();/// <summary>/// 關閉當前面板的時候調用/// </summary>public abstract void OnExit(); }UIManager
管理所有的UI,提供生成UI和關閉UI的接口,制定調用BasePanel的三個函數的邏輯。
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 管理所有UI,由于項目并不是很大,所以現階段沒有使用json存儲所有的UI類型,UI的存取通過對象池來獲得 /// 在場景切換的時候需要把數據結構清空 /// </summary> public class UIManager : BaseManager<UIManager> {/// <summary>/// 管理當前場景的UI的棧/// </summary>private Stack<BasePanel> panelStack;/// <summary>/// 管理狀態(面板)的字典/// </summary>private Dictionary<PanelType, BasePanel> panelDict;private Transform canvasTransform;/// <summary>/// 返回面板類型對應字符串,便于對象池生成 /// </summary>/// <param name="newPanel"></param>private string GetPanelString(PanelType type){switch (type){case PanelType.StartPanel:return "StartPanel";case PanelType.TestPanel:return "TestPanel";case PanelType.TestPanel2:return "TestPanel2";default:Debug.Log($"不存在{type.ToString()}面板");break;}return "\0";}private Transform CanvasTransform {get {if(canvasTransform == null){canvasTransform = GameObject.Find("Canvas").transform;}return canvasTransform;}}public GameObject currentPanel;public UIManager(){panelStack = new Stack<BasePanel>();}private BasePanel GetUI(PanelType panelType){if(panelDict == null){panelDict = new Dictionary<PanelType, BasePanel>();}BasePanel panel;if(!panelDict.TryGetValue(panelType, out panel)){GameObject curPanel = PoolManager.GetInstance().GetObject(GetPanelString(panelType), CanvasTransform.position);curPanel.transform.SetParent(CanvasTransform);panel = curPanel.GetComponent<BasePanel>();panelDict.Add(panelType, panel);}else{panel = panelDict[panelType];GameObject curPanel = PoolManager.GetInstance().GetObject(GetPanelString(panelType), CanvasTransform.position);}return panel;}/// <summary>/// 推入一個面板/// </summary>/// <param name="newPanel"></param>public void PushPanel(PanelType panelType){if(panelStack == null){panelStack = new Stack<BasePanel>();}if(panelStack.Count > 0){BasePanel topPanel = panelStack.Peek();topPanel.OnPause();}BasePanel panel = GetUI(panelType);panelStack.Push(panel);panel.OnEnter();}/// <summary>/// 彈出面板/// </summary>public void PopPanel(){if(panelStack == null){panelStack = new Stack<BasePanel>();}if(panelStack.Count<=0){return;}//退出棧頂面板BasePanel topPanel = panelStack.Pop();topPanel.OnExit();//恢復上一個面板if (panelStack.Count > 0){BasePanel panel = panelStack.Peek();panel.OnResume();}} }舉個
實現一個負責開啟兩個面板的主面板
testButton1可以用find也可以直接拖拽賦值
GameManager
這里只負責一開始生成開始面板,掛載到主相機上面
using System.Collections; using System.Collections.Generic; using UnityEngine;public class GameManager : MonoBehaviour {// Start is called before the first frame updatevoid Start(){UIManager.GetInstance().PushPanel(PanelType.StartPanel);}// Update is called once per framevoid Update(){} }運行結果如下
TestPanel1/ TestPanel2
測試面板,只能開啟其中一個,一個開啟后,StartPanel的按鈕將不會再生效,直到關閉
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class TestPanel : BasePanel {public Button exitButton;private CanvasGroup m_CanvasGroup;private void Start(){exitButton.onClick.AddListener(exitButtonAction);}public override void OnEnter(){Debug.Log("打開測試界面1");}public override void OnExit(){Debug.Log("測試界面1退出");PoolManager.GetInstance().PushObj("TestPanel", this.gameObject);}public override void OnPause(){Debug.Log("測試界面1被覆蓋");m_CanvasGroup.blocksRaycasts = false;}public override void OnResume(){Debug.Log("測試界面1恢復");m_CanvasGroup.blocksRaycasts = true;}private void exitButtonAction(){UIManager.GetInstance().PopPanel();} } using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class TestPanel2 : BasePanel {public Button exitButton;private CanvasGroup m_CanvasGroup;private void Start(){exitButton.onClick.AddListener(exitButtonAction);}public override void OnEnter(){Debug.Log("打開測試界面2");}public override void OnExit(){Debug.Log("測試界面2退出");PoolManager.GetInstance().PushObj("TestPanel2", this.gameObject);}public override void OnPause(){Debug.Log("測試界面2被覆蓋");m_CanvasGroup.blocksRaycasts = false;}public override void OnResume(){Debug.Log("測試界面2恢復");m_CanvasGroup.blocksRaycasts = true;}private void exitButtonAction(){UIManager.GetInstance().PopPanel();} }分別掛載到兩個面板上
接下來測試
1. 按下測試按鈕一、testPanel1出現
2. 嘗試按下測試按鈕二、沒有反應
3. 關閉測試面板一后再次按下測試按鈕二,出現測試面板二,并且一失活進入對象池
4. 同理嘗試按下測試按鈕一、沒有反應
ヾ(?゚▽゚)ノ說明成功了
ps:這里生成的UI并沒有按照預制體之前的位置放在左右上角,根據更新所示的那樣就行了
總結
很多情況下,當一個UI出現時我們都需要把其他UI的交互關閉,否則經常會造成各種bug,所以管理UI還是非常重要的。
總結
以上是生活随笔為你收集整理的Unity基础UI框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Unity 基础纹理
- 下一篇: [Unity基础]01Unity基本操作