Unity:2021.1.14flc1
在B站跟着视频
[Unity编程]这大概是最好理解的UI框架了吧搭建的一个UGUI的框架,处理了一些小问题,参考MissingReferenceException: The object of type ‘GameObject‘ has been destroye
整个框架分层比较乱,而且实际运行的话要根据你在unity工程里面具体的资源放置来修改代码里的资源路径,所以这里主要是给我自己做个记录
UIType.cs
/*
存储单个UI的信息,包括名字和路径
*/
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.cs
/// <summary>
/// 所有UI面板的父类,包含UI面板的状态信息
/// </summary>
public class BasePanel
{
/// <summary>
/// UI信息
/// </summary>
public UIType UIType { get; private set; }
/// <summary>
/// UI管理工具
/// </summary>
public UITool UITool { get; private set; }
/// <summary>
/// 面板管理器
/// </summary>
public PanelManager PanelManager { get; private set; }
/// <summary>
/// UI管理器
/// </summary>
public UIManager UIManager { get; private set; }
public BasePanel(UIType uiType)
{
UIType = uiType;
}
/// <summary>
/// 初始化UITool
/// </summary>
/// <param name="tool"></param>
public void Initialize(UITool tool)
{
UITool = tool;
}
/// <summary>
/// 初始化面板管理器
/// </summary>
/// <param name="panelManager"></param>
public void Initialize(PanelManager panelManager)
{
PanelManager = panelManager;
}
/// <summary>
/// 初始化UI管理器
/// </summary>
/// <param name="uiManager"></param>
public void Initialize(UIManager uiManager)
{
UIManager = uiManager;
}
/// <summary>
/// UI进入操作
/// </summary>
public virtual void OnEnter() { }
/// <summary>
/// UI暂停操作
/// </summary>
public virtual void OnPause()
{
UITool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false;
}
/// <summary>
/// UI继续操作
/// </summary>
public virtual void OnResume()
{
UITool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = true;
}
/// <summary>
/// UI退出操作
/// </summary>
public virtual void OnExit()
{
UIManager.DestroyUI(UIType);
}
}
UIManager.cs
/// <summary>
/// //存储所有UI信息,并可以创建或者销毁UI
/// </summary>
public class UIManager
{
/// <summary>
/// 存储所有UI信息的字典,每一个UI信息都会对应一个GameObject
/// </summary>
private Dictionary<UIType, GameObject> dicUI;
public UIManager()
{
dicUI = new Dictionary<UIType, GameObject>();
}
/// <summary>
/// 获取一个UI对象
/// </summary>
/// <param name="type">UI信息</param>
/// <returns></returns>
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;
}
/// <summary>
/// 销毁一个对象
/// </summary>
/// <param name="type">UI信息</param>
public void DestroyUI(UIType type)
{
if (dicUI.ContainsKey(type))
{
GameObject.Destroy(dicUI[type]);
dicUI.Remove(type);
}
}
}
PanelManager.cs
/// <summary>
/// 面板管理器,用栈来存储UI
/// </summary>
public class PanelManager
{
/// <summary>
/// 存储UI面板的栈
/// </summary>
private Stack<BasePanel> stackPanel;
/// <summary>
/// UI管理器
/// </summary>
private UIManager uiManager;
private BasePanel panel;
public PanelManager()
{
stackPanel = new Stack<BasePanel>();
uiManager = new UIManager();
}
/// <summary>
/// UI的入栈操作,此操作会显示一个面板
/// </summary>
/// <param name="nextPanel">要显示的面板</param>
public void Push(BasePanel nextPanel)
{
if (stackPanel.Count > 0)
{
stackPanel.Peek().OnPause();
}
stackPanel.Push(nextPanel);
GameObject panelGo = uiManager.GetSingleUI(nextPanel.UIType);
nextPanel.Initialize(new UITool(panelGo));
nextPanel.Initialize(this);
nextPanel.Initialize(uiManager);
nextPanel.OnEnter();
}
/// <summary>
/// UI的出栈操作
/// </summary>
public void Pop()
{
if (stackPanel.Count > 0)
stackPanel.Pop().OnExit();
if (stackPanel.Count > 0)
stackPanel.Peek().OnResume();
}
/// <summary>
/// 执行所有面板的OnExit()
/// </summary>
public void PopAll()
{
while (stackPanel.Count > 0)
{
stackPanel.Pop().OnExit();
}
}
}
MainPanel.cs
/// <summary>
/// Main场景的主面板
/// </summary>
public class MainPanel : BasePanel
{
static readonly string path = "Prefabs/UI/Panel/MainPanel";
public MainPanel() : base(new UIType(path)) { }
public override void OnEnter()
{
UITool.GetOrAddComponentInChildren<Button>("Button").onClick.AddListener(() =>
{
GameRoot.Instance.SceneSystem.SetScene(new StartScene());
PanelManager.Pop();
});
}
}
StartPanel.cs
/// <summary>
/// 开始主面板
/// </summary>
public class StartPanel : BasePanel
{
static readonly string path = "Prefabs/UI/Panel/StartPanel 1";
public StartPanel():base(new UIType(path)){ }
public override void OnEnter()
{
UITool.GetOrAddComponentInChildren<Button>("Button").onClick.AddListener(() =>
{
//点击事件可以写在这里
Debug.Log("按钮被点击了");
PanelManager.Push(new SettingPanel());
});
UITool.GetOrAddComponentInChildren<Button>("Play Button").onClick.AddListener(() =>
{
//点击事件可以写在这里
GameRoot.Instance.SceneSystem.SetScene(new MainScene());
/* PanelManager.Pop();*/
});
}
}
UITool.cs
/// <summary>
/// UI管理工具,包括获取某个子对象组件的操作
/// </summary>
public class UITool
{
/// <summary>
/// 当前的活动面板
/// </summary>
GameObject activePanel;
public UITool(GameObject gameObject)
{
activePanel = gameObject;
}
/// <summary>
/// 给当前的活动面板获取或添加一个组件
/// </summary>
/// <typeparam name="T">组件类型</typeparam>
/// <returns></returns>
public T GetOrAddComponent<T>() where T : Component
{
if (activePanel.GetComponent<T>() == null)
activePanel.AddComponent<T>();
return activePanel.GetComponent<T>();
}
/// <summary>
/// 根据名称查找一个子对象
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public GameObject FindChildGameObject(string name)
{
Transform[] trans = activePanel.GetComponentsInChildren<Transform>();
foreach(Transform item in trans)
{
if (item.name == name)
{
return item.gameObject;
}
}
Debug.LogWarning($"{activePanel.name}里找不到名为{name}的子对象");
return null;
}
/// <summary>
/// 根据名称获取一个子对象的组件
/// </summary>
/// <typeparam name="T">组件类型</typeparam>
/// <param name="name">子对象的名称</param>
/// <returns></returns>
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;
}
}
SceneSystem.cs
/// <summary>
/// 场景的状态管理系统
/// </summary>
public class SceneSystem
{
/// <summary>
/// 场景状态类
/// </summary>
SceneState sceneState;
/// <summary>
/// 设置当前场景并进入当前场景
/// </summary>
/// <param name="state"></param>
public void SetScene(SceneState state)
{
/*if (sceneState != null)
sceneState.OnExit();
sceneState = state;
if (sceneState != null)
sceneState.OnEnter();*/
sceneState?.OnExit();
Debug.Log("okOnExit" + state.ToString());
sceneState = state;
sceneState?.OnEnter();
Debug.Log("okOnEnter" + state.ToString());
}
}
SceneState.cs
public abstract class SceneState
{
/// <summary>
/// 场景进入时执行的操作
/// </summary>
public abstract void OnEnter();
/// <summary>
/// 场景退出时执行的操作
/// </summary>
public abstract void OnExit();
}
MainScene.cs
/// <summary>
/// Main场景
/// </summary>
public class MainScene : SceneState
{
readonly string sceneName = "Main";
PanelManager panelManager;
public override void OnEnter()
{
Debug.Log("Main 的 OnEnter执行了");
panelManager = new PanelManager();
if (SceneManager.GetActiveScene().name != sceneName)
{
SceneManager.LoadScene(sceneName);
SceneManager.sceneLoaded += SceneLoaded;
}
else
{
panelManager.Push(new StartPanel());
GameRoot.Instance.SetActive(panelManager.Push);
}
}
public override void OnExit()
{
SceneManager.sceneLoaded -= SceneLoaded;
panelManager.PopAll();
}
/// <summary>
/// 场景加载完毕之后执行的方法
/// </summary>
/// <param name="scene"></param>
/// <param name="load"></param>
private void SceneLoaded(Scene scene, LoadSceneMode load)
{
panelManager.Push(new MainPanel());
GameRoot.Instance.SetActive(panelManager.Push);
Debug.Log($"{sceneName}场景加载完毕!");
}
}
StartScene.cs
/// <summary>
/// 开始场景
/// </summary>
public class StartScene : SceneState
{
readonly string sceneName = "Start";
PanelManager panelManager;
public override void OnEnter()
{
panelManager = new PanelManager();
if (SceneManager.GetActiveScene().name != sceneName)
{
SceneManager.LoadScene(sceneName);
SceneManager.sceneLoaded += SceneLoaded;
}
else
{
panelManager.Push(new StartPanel());
GameRoot.Instance.SetActive(panelManager.Push);
}
}
public override void OnExit()
{
SceneManager.sceneLoaded -= SceneLoaded;
panelManager.PopAll();
}
/// <summary>
/// 场景加载完毕之后执行的方法
/// </summary>
/// <param name="scene"></param>
/// <param name="load"></param>
private void SceneLoaded(Scene scene,LoadSceneMode load)
{
panelManager.Push(new StartPanel());
GameRoot.Instance.SetActive(panelManager.Push);
Debug.Log($"{sceneName}场景加载完毕!");
}
}
GameRoot.cs
/// <summary>
/// 管理全局的一些东西
/// </summary>
public class GameRoot : MonoBehaviour
{
public static GameRoot Instance { get; private set; }
/// <summary>
/// 场景管理器
/// </summary>
public SceneSystem SceneSystem { get; private set; }
/// <summary>
/// 显示一个面板
/// </summary>
public UnityAction<BasePanel> Push { get; private set; }
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(this.gameObject);
}
else
{
Instance = this;
}
SceneSystem = new SceneSystem();
DontDestroyOnLoad(this.gameObject);
/*if (Instance == null)
Instance = this;
else
Destroy(gameObject);
Instance = this;
DontDestroyOnLoad(gameObject);*/
}
void Start()
{
SceneSystem.SetScene(new StartScene());
}
public void SetActive(UnityAction<BasePanel> push)
{
Push = push;
}
}