赞
踩
知识介绍:
c# 属性: public int Id { get; private set; }
说明Id这个属性在其所在的类外被调用时,只能获取它的值而不能设置它的值
用来存放预制体中该UI的名字以及路径,基础面板含有这个对象。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class UIType { public string Name { get; private set; } /// <summary> /// UI路径 /// </summary> public string Path { get; private set; } public UIType(string path) { Path = path; Name = path.Substring(path.LastIndexOf('/') + 1); } }
这些文件的路径随后需要通过代码进行获取:
它是所有面板类的基类,当需要新的面板时,首先需要继承该类。
它需要一个UIType,记录它需要的预制体的路径及名字
然后,对于一个面板来说,存在四种状态
using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class BasePanel { public UIType UIType { get; private set; } public BasePanel(UIType uIType) { UIType = uIType; } public virtual void OnEnter() { } public virtual void OnPause() { } /// <summary> /// UI继续时的操作 /// </summary> public virtual void OnResume() { } public virtual void OnExit() { } }
例如当从开始界面调出设置界面的时候,此时无法再对开始界面的按钮进行操作,因此此时也就是OnPause状态
每一个面板下面可能有很多个UI属性,因此每个面板都需要一个UI管理器,它有获取面板下的UI,创建UI,或者销毁UI的功能。
首先需要掌握Instantiate函数的用法,因为我们接下来需要生成预制体。
Instantiate函数是unity3d中进行实例化的函数,也就是对一个对象进行复制操作的函数,这个函数共有五个重载(overloaded)函数,对这五个函数的理解不清楚的话产生的效果也不相同,现在对这五个函数做一定的理解。
先附上unity3d API 中对这个函数的描述:
Instantiate函数实例化是将original对象的所有子物体和子组件完全复制,成为一个新的对象。这个新的对象拥有与源对象完全一样的东西,包括坐标值等。
original:用来做复制操作的对像物体,源对象
position:实例化的对象的位置坐标
rotation:实例化的对象的旋转坐标(旋转四元数)
parent:实例化对象的父对象,就是给这个实例化对象找的爹,在完成实例化函数处理后,实例化对象将在父对象下,是父对象的子对象
instantiateWorldSpace(老的叫WorldSpaceStays):这个值为TRUE,表示实例化对象相对于世界坐标系的位置(是位置,不是坐标值,比如实例化前在Canvas左上角,实例化后还在左上角)不变,相对于父对象的坐标值变了。为false,表示实例化对象相对于父对象的坐标值不变,但在世界坐标系中的位置变了。
这两个函数的区别是instantiateWorldSpace等于true/false的区别。
第一个函数相当于instantiateWorldSpace等于false。效果:实例化对象将放在父对象下,完全保存了源对象的属性,其位置坐标值是相对于父对象的,值不变,在世界坐标系下位置发生变化。
第二个函数相当于instantiateWorldSpace等于TRUE。效果:实例化对象将放在父对象下,完全保存了源对象的属性,其位置坐标值是相对于父对象的,值改变,在世界坐标系下位置不发生变化。
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 存储所有UI信息,并可以创建或者销毁UI /// </summary> public class UIManager { // Start is called before the first frame update /// <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);//此处是在Canvas下生成预制体,函数使用方法见上面解析 ui.name = type.Name; return ui; } /// <summary> /// 销毁一个UI对象 /// </summary> /// <param name="type">UI信息</param> public void DestroyUI(UIType type) { if (dicUI.ContainsKey(type)) { DestroyUI(type); dicUI.Remove(type); } } }
对于一个面板来说,我们可能会需要通过点击这个面板下的按钮然后开启新的面板,当我们开启一个新的面板时,我们可能无法操作原来的那个面板,因此此时就需要让原来的那个面板执行暂停功能。
而当我们连续开启多个面板时,然后再一个个关闭,为了保证顺序,那么此时需要用到栈的结构。
当新的面板出现时,需要暂停原来的面板。
关闭面板时,需要执行该面板的Exit工作,然后将其Pop出来,当Pop面板后,如果当前还有面板,我们需要将该面板由暂停功能恢复到正常状态的功能,因此执行OnResume函数。
PanelManager还有一个功能就是调用UIManager来生成预制体,采用这个函数:
uiManager.GetSingleUI(nextPanel.UIType);每次Push的时候都要调用这个函数,这样才能生成预制体。
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <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)//如果当前没有面板,则不需要执行暂停面板的操作 { panel = stackPanel.Peek();//获取栈顶 panel.OnPause(); } stackPanel.Push(nextPanel); GameObject panelGo = uiManager.GetSingleUI(nextPanel.UIType); } /// <summary> /// 执行面板的出栈操作,此操作会执行面版的OnExit方法 /// </summary> public void Pop() { if (stackPanel.Count > 0) { stackPanel.Peek().OnExit(); stackPanel.Pop(); } if (stackPanel.Count > 0) stackPanel.Peek().OnResume(); } }
接下来可以创建实例面板的脚本了。
StartPanel:
它需要带有预制体的路径,然后用路径创建一个UIType,然后用UIType来作为基类构造函数的参数。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// 开始主面板
/// </summary>
public class StartPanel :BasePanel
{
static readonly string path = "Prefabs/UI/Panel/StartPanel";
public StartPanel():base(new UIType(path)) { }//用预制体的路径创建一个UIType,并且将这个UIType作为参数,然后去调用基类的构造函数。
}
有了上面那个脚本之后,我们只需要在
StartManager:
创建一个StartManager脚本,并且生成上面的那个StartPanel,并将其Push放入PanelManager即可产生StartPanel面板
using System.Collections; using System.Collections.Generic; using UnityEngine; public class StartManager : MonoBehaviour { PanelManager panelManager; // Start is called before the first frame update private void Awake() { panelManager = new PanelManager(); } void Start() { panelManager.Push(new StartPanel()); } // Update is called once per frame }
接下来实现场景间的跳转
首先书写一个SceneState,作为抽象基类,包含有进入场景和退出场景操作的方法
using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class SceneState { /// <summary> /// 场景进入时执行的操作 /// </summary> public abstract void OnEnter(); /// <summary> /// 场景退出时执行的操作 /// </summary> public abstract void OnExit(); }
接下来书写一个开始场景,继承初始场景
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class StartScene :SceneState { /// <summary> /// 场景名称 /// </summary> 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()); } } public override void OnExit() { SceneManager.sceneLoaded -= SceneLoaded; } /// <summary> /// 场景加载完毕后执行的方法 /// </summary> /// <param name="scene"></param> /// <param name="load"></param> private void SceneLoaded(Scene scene, LoadSceneMode load) { panelManager.Push(new StartPanel()); Debug.Log($"{sceneName}场景加载完毕"); } }
事实上,在阅读上面的代码的时候,你可能会产生了这样的问题,这是委托的用法
C#委托可以查看我写的另外一篇文章
然后再仿照上面,书写一个主场景MainScene
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class MainScene :SceneState { // Start is called before the first frame update /// <summary> /// 场景名称 /// </summary> readonly string sceneName = "Main"; PanelManager panelManager; public override void OnEnter() { panelManager = new PanelManager(); if (SceneManager.GetActiveScene().name != sceneName) { SceneManager.LoadScene(sceneName); SceneManager.sceneLoaded += SceneLoaded;//将函数委托于sceneLoaded上。Unity的机制中,当加载场景时,会自动调用SceneLoaded。而我们只需要将函数委托于其上,就可以在加载场景时调用我们委托与其上的函数了。 } else { panelManager.Push(new StartPanel()); } } public override void OnExit() { SceneManager.sceneLoaded -= SceneLoaded; } /// <summary> /// 场景加载完毕后执行的方法 /// </summary> /// <param name="scene"></param> /// <param name="load"></param> private void SceneLoaded(Scene scene, LoadSceneMode load) { Debug.Log($"{sceneName}场景加载完毕"); } }
再书写一个场景的状态管理系统,其实它只有一个函数,就是设置当前场景为所需要的场景。
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <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();//这段书写方式和上面那段代码是相同的意义 //sceneState = state; //sceneState?.OnEnter(); } }
再创建一个GameRoot ,然后在unity中用空物体挂接这个脚本,它用来生成场景
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> ///管理全局的一些东西 /// </summary> public class GameRoot : MonoBehaviour { public static GameRoot Instance { get; private set; } public SceneSystem SceneSystem { get; private set; } private void Awake() { Instance = this; SceneSystem = new SceneSystem(); } private void Start() { SceneSystem.SetScene(new StartScene()); } }
然后在StartPanel中添加Start的按键:
并且在StartPanel的面板中添加跳转的按钮,然后想要按下按钮时跳转,写下以下脚本:
此时,点击按钮便可以成功从Start场景跳转至Main场景了
但是我们注意到,当进入Main场景时,并没有面板被推出,于是为此,首先需要写一个MainPanel的代码:
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; /// <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() { } }
然后修改MainScene,下面这个方法是加载完场景后调用的,我们在场景加载完后推出新面板:
此时按下主面板的开始建
即可跳转到Start界面并推出Panel
当从Start场景跳转到主场景时会发现,GameRoot就没了,这样就不好管理跳转回去,
为此,我们添加这样的函数:
此时即使跳转,GameRoot也不会消失
接下来实现当按下MainPanel的按键时,返回主场景的功能:
于是需要在MainPanel中添加一个右上角的关闭按键
做到这里后即可实现按下主场景中的叉键场景跳转,但是出现了一个问题,当再次回到主场景时,多了一个GameRoot
为了防止这种情况,我们可以
然后在每个场景结束时,都弹出所有面板
同理MainScene也这样做:
像这样:
还有一个优化就是,我们可能会在框架以外的地方用到Push或者Pop,所以可以在这里定义一个:
然后就可以在Scene的脚本中:
用来存放预制体中该UI的名字以及路径,基础面板含有这个对象。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class UIType { public string Name { get; private set; } /// <summary> /// UI路径 /// </summary> public string Path { get; private set; } public UIType(string path) { Path = path; Name = path.Substring(path.LastIndexOf('/') + 1); } }
所有面板类的基类,当需要新的面板时,首先需要继承该类。
对于一个面板来说,存在四种状态,c
using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class BasePanel { /// <summary> /// UI信息 /// </summary> public UIType UIType { get; private set; } /// <summary> /// UI管理工具 /// </summary> 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; } /// <summary> /// 初始化面板管理器 /// </summary> /// <param name="panelManager"></param> public void Initialize(PanelManager panelManager) { PanelManager = panelManager; } public void Initialize(UIManager uiManager) { UIManager = uiManager; } public virtual void OnEnter() { } public virtual void OnPause() { UITool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false; } /// <summary> /// UI继续时的操作 /// </summary> public virtual void OnResume() { UITool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = true; } public virtual void OnExit() { UIManager.DestroyUI(UIType); } public void Push(BasePanel panel) => PanelManager?.Push(panel); //注意,上行这种写法和下行一样: /*public void Push(BasePanel panel) { PanelManager?.Push(panel); }*/ public void Pop() => PanelManager?.Pop(); }
每一个面板下面可能有很多个UI属性,因此每个面板都需要一个UI管理器,它有获取面板下的UI,创建UI,或者销毁UI的功能
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 存储所有UI信息,并可以创建或者销毁UI /// </summary> public class UIManager { // Start is called before the first frame update /// <summary> /// 存储所有UI信息的字典,每一个UI信息都会对应一个GameObject /// </summary> private Dictionary<UIType, GameObject> dicUI; public UIManager() { dicUI = new Dictionary<UIType, GameObject>(); } /// <summary> /// 获取当前面板下的某个UI对象,如果没有该UI对象,我们则创建一个 /// </summary> /// <param name="type">UI信息</param> /// <returns></returns> public GameObject GetSingleUI(UIType type) { //在每个面板中,其UI信息都存放在Canva(画布下),画布和画布中的所有信息就组成了一个面板,因此首先需要找到这个画布 GameObject parent = GameObject.Find("Canvas");//在游戏中查找名为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> /// 销毁一个UI对象 /// </summary> /// <param name="type">UI信息</param> public void DestroyUI(UIType type) { if (dicUI.ContainsKey(type)) { GameObject.Destroy(dicUI[type]); dicUI.Remove(type); } } }
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <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) { 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(); } /// <summary> /// 执行面板的出栈操作,此操作会执行面版的OnExit方法 /// </summary> public void Pop() { if (stackPanel.Count > 0) { stackPanel.Pop().OnExit(); //把这个面板给弹出,↓如果这个面板还有的话就继续 } if (stackPanel.Count > 0) stackPanel.Peek().OnResume(); } public void PopAll() { while (stackPanel.Count > 0) stackPanel.Pop().OnExit(); } }
上面就是创建一个面板所需要的脚本,接下来我们创建一个实例面板脚本,它需要预制体的路径。
并且我们需要对这个面板进行操作,因此需要重载OnEnter函数。
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; /// <summary> /// 开始主面板 /// </summary> public class StartPanel :BasePanel { static readonly string path = "Prefabs/UI/Panel/StartPanel"; public StartPanel():base(new UIType(path)) { } public override void OnEnter() { //base.OnEnter(); UITool.GetOrAddComponentInChildren<Button>("Setting").onClick.AddListener(() => { //点击事件可以写在这里面 Debug.Log("点击了设置按钮"); //PanelManager.Push(new SettingPanel()); Push(new SettingPanel()); }); UITool.GetOrAddComponentInChildren<Button>("Play").onClick.AddListener(() => { //点击事件可以写在这里面 //Debug.Log("点击了设置按钮"); GameRoot.Instance.SceneSystem.SetScene(new MainScene()); }); } }
在面板里,我们有时需要获取/添加这个面板下的一些组件,或者是获取/添加其子对象的组件,我们可以将其放在BasePanel中实现。
但是我们可以书写一个工具类UITool,将这些函数放在UITool类中实现,然后让BasePanel有UITool类这个子对象,然后只需要让BasePanel调用UITool类中的找组件函数即可实现。
using System.Collections; using System.Collections.Generic; using UnityEngine; public class UITool { /// <summary> /// 当前的活动面板 /// </summary> GameObject activePanel; public UITool(GameObject panel) { activePanel = panel; } /// <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>(); } else return null; } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; public class SettingPanel : BasePanel { static readonly string path = "Prefabs/UI/Panel/SettingPanel"; public SettingPanel() : base(new UIType(path)) { } public override void OnEnter() { //base.OnEnter(); UITool.GetOrAddComponentInChildren<Button>("Setting2").onClick.AddListener(() => { //点击事件可以写在这里面 Debug.Log("点击了设置2按钮"); PanelManager.Push(new SettingPanel2()); }); UITool.GetOrAddComponentInChildren<Button>("Exit").onClick.AddListener(() => { //点击事件可以写在这里面 Debug.Log("点击了退出设置按钮"); PanelManager.Pop(); }); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; public class StartManager : MonoBehaviour { PanelManager panelManager; // Start is called before the first frame update private void Awake() { panelManager = new PanelManager(); } void Start() { panelManager.Push(new StartPanel()); } // Update is called once per frame } / <summary> / / </summary> //public class UITool //{ // /// <summary> // /// 当前的活动面板 // /// </summary> // GameObject activePanel; // public UITool(GameObject panel) // { // activePanel = panel; // } // /// <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>(); // } // else return null; //} / / SettingPanel(此处复制粘贴StartPanel //using UnityEngine.UI; //public class SettingPanel : BasePanel //{ // static readonly string path = "Prefabs/UI/Panel/SettingPanel"; // public SettingPanel() : base(new UIType(path)) { } // public override void OnEnter() // { // //base.OnEnter(); // //UITool.GetOrAddComponentInChildren<Button>("BtnSetting").onClick.AddListener(() => // //{ // //点击事件可以写在这里面 // // Debug.Log("点击了设置按钮"); // // PanelManager.Push(new SettingPanel()); // //}) // UITool.GetOrAddComponentInChildren<Button>("BtnExit").onClick.AddListener(() => // { // PanelManager.Pop(); // }); // } // public override void OnExit() // { // //base.OnExit(); // UIManager.DestroyUI(UIType); // } // /// <summary> // /// 下面这两个函数是为了在点开设置面板时,封面的按钮设置应该关掉,所以此时应该将下面这两个函数放在StartPanel,或者可以直接放在BasePanel里面 // /// </summary> // public override void OnPause() // { // UITool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false; // } // public override void OnResume() // { // UITool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false; // } //} /接下来需要 减少设置面板 /SceneState.cs / // ///场景状态 //public abstract class SceneState //{ // /// <summary> // /// 场景进入时执行的操作 // /// </summary> // public abstract void OnEnter(); // /// <summary> // /// 场景退出时执行的操作 // /// </summary> // public abstract void OnExit(); //} /开始场景 /using UnityEngine.SceneManagement //public class StartScene : SceneState //{ // /// <summary> // /// 场景名称 // /// </summary> // 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()); // } // } // public override void OnExit() // { // SceneManager.sceneLoaded -= SceneLoaded; // } // /// <summary> // /// 场景加载完毕后执行的方法 // /// </summary> // /// <param name="scene"></param> // /// <param name="load"></param> // private void SceneLoaded(Scene scene,LoadSceneMode load) // { // Debug.Log($"{sceneName}场景加载完毕"); // } //} /MainScene 复制上面的StartScene / /SceneSystem.cs / //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(); // sceneState = state; // sceneState?.OnEnter(); // } //} GameRoot.cs /管理全局的一些东西 //public class GameRoot : MonoBehaviour //{ // public static GameRoot Instance { get; private set; } // public SceneSystem SceneSystem { get; private set; } // private void Awake() // { // Instance = this; // SceneSystem = new SceneSystem(); // } // private void Start() // { // SceneSystem.SetScene(new StartScene()); // } //} /MainPanel /main场景的主面板 /
using System.Collections; using System.Collections.Generic; using UnityEngine; public abstract class SceneState { /// <summary> /// 场景进入时执行的操作 /// </summary> public abstract void OnEnter(); /// <summary> /// 场景退出时执行的操作 /// </summary> public abstract void OnExit(); }
using System.Collections; using System.Collections.Generic; using UnityEngine; /// <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(); //sceneState = state; //sceneState?.OnEnter(); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class StartScene :SceneState { /// <summary> /// 场景名称 /// </summary> 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()); } } 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.SetAction(panelManager.Push);优化 Debug.Log($"{sceneName}场景加载完毕"); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.SceneManagement; public class MainScene :SceneState { // Start is called before the first frame update /// <summary> /// 场景名称 /// </summary> readonly string sceneName = "Main"; 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.SetAction(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.SetAction(panelManager.Push); Debug.Log($"{sceneName}场景加载完毕"); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; /// <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() { base.OnEnter(); UITool.GetOrAddComponentInChildren<Button>("Quit").onClick.AddListener(() => { //点击事件可以写在这里面 GameRoot.Instance.SceneSystem.SetScene(new StartScene()); //PanelManager.Pop(); Pop(); }); } }
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; /// <summary> ///管理全局的一些东西 /// </summary> public class GameRoot : MonoBehaviour { public static GameRoot Instance { get; private set; } public SceneSystem SceneSystem { get; private set; } /// <summary> /// 显示一个面板 /// </summary> public UnityAction<BasePanel> Push { get; private set; } public void SetAction(UnityAction<BasePanel> push) { Push = push; } private void Awake() { if (Instance == null) Instance = this; else Destroy(gameObject); SceneSystem = new SceneSystem(); DontDestroyOnLoad(gameObject); } private void Start() { SceneSystem.SetScene(new StartScene()); } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。