当前位置:   article > 正文

Unity UI框架_public class uimainscene : scenebase { //进入时 publi

public class uimainscene : scenebase { //进入时 public override void onenter

窗口管理

初始化

在场景中挂载一个脚本,用于创建初始界面

  1. using UnityEngine;
  2. //创建开始界面
  3. public class CreateStartPanel : MonoBehaviour
  4. {
  5. //面板顺序管理器
  6. PanelStack panelStack;
  7. void Awake()
  8. {
  9. panelStack = new PanelStack();
  10. }
  11. void Start()
  12. {
  13. //打开初始面板
  14. panelStack.Push(new StartPanel());
  15. }
  16. }

初始界面

初始界面面板的控制脚本,不用挂载到面板的预制体上

生成面板的时候,直接new一个该类的实例即可

初始界面有一个Open按钮,在预制体中是没有添加点击事件

在面板打开之后,动态地添加点击事件,按下可以打开一个子窗口

  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. //开始面板
  4. public class StartPanel : BasePanel
  5. {
  6. //面板存储在Resource/Prefabs目录下:路径从Prefabs开始,需要包含文件名,不用加文件后缀
  7. static readonly string path="Prefabs/StartPanel";
  8. public StartPanel():base(new PanelType(path)){ Debug.Log("派生类构造函数"); }
  9. //重写进入函数
  10. public override void OnEnter()
  11. {
  12. //给指定的按钮添加点击事件
  13. panelExtensionTool.GetOrAddComponentInChildren<Button>("OpenAnotherPanelBtn").onClick.AddListener(()=>
  14. {
  15. //打开子窗口
  16. PanelStack.Push(new ChildrenPanel());
  17. }
  18. );
  19. panelExtensionTool.GetOrAddComponentInChildren<Button>("MainSceneBtn").onClick.AddListener(() =>
  20. {
  21. //使用单例切换场景
  22. GameManager.instance.sceneSystem.SetScene(new MainScene());
  23. //弹出场景中的所有面板
  24. PanelStack.PopAll();
  25. }
  26. );
  27. }
  28. //重写退出函数
  29. public override void OnExit()
  30. {
  31. //关闭面板
  32. PanelManager.DestroyPanel(this.PanelType);
  33. }
  34. //暂停:使窗口不能交互
  35. public override void OnPause()
  36. {
  37. //也可以写在基类中
  38. panelExtensionTool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false;
  39. }
  40. //恢复:使窗口可以交互
  41. public override void OnResume()
  42. {
  43. panelExtensionTool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = true;
  44. }
  45. }

子窗口

子界面有一个Close按钮,在预制体中是没有添加点击事件

在面板打开之后,动态地添加点击事件,按下可以关闭这个子窗口

  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. //子面板
  4. public class ChildrenPanel: BasePanel
  5. {
  6. static readonly string path = "Prefabs/ChildrenPanel";
  7. public ChildrenPanel() : base(new PanelType(path)) { }
  8. public override void OnEnter()
  9. {
  10. //给指定的按钮添加点击事件
  11. panelExtensionTool.GetOrAddComponentInChildren<Button>("Close").onClick.AddListener(() =>
  12. {
  13. //关闭面板
  14. PanelStack.Pop();
  15. }
  16. );
  17. }
  18. public override void OnExit()
  19. {
  20. PanelManager.DestroyPanel(this.PanelType);
  21. }
  22. public override void OnPause()
  23. {
  24. panelExtensionTool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false;
  25. }
  26. public override void OnResume()
  27. {
  28. panelExtensionTool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = true;
  29. }
  30. }

面板类型信息

面板的类型信息,用于区分不同类型的面板

  1. /// <summary>
  2. /// 面板的类型信息
  3. /// </summary>
  4. public class PanelType
  5. {
  6. /// <summary>
  7. /// 面板的名称
  8. /// </summary>
  9. public string Name;
  10. /// <summary>
  11. /// 面板的存储路径
  12. /// </summary>
  13. public string Path;
  14. public PanelType(string path)
  15. {
  16. Path = path;
  17. //截取斜杠后的全部字符
  18. Name = path.Substring(path.LastIndexOf('/') + 1);
  19. }
  20. }

基础面板

每一个面板都需要基础这个基础面板类

基础面板类保存面板的类型信息

对于面板有四个基本状态,分别是打开、关闭、暂停、恢复

在状态发生转换时,需要执行对应的函数,完成相应的操作

这四个事件函数在基类中被声明为虚函数,需要继承的派生类将它们重写、实现

此外,基础面板还保存了面板扩展工具、面板栈、面板管理器的引用及其属性,以及相应的初始化函数,这样就可以方便地对面板进行管理

  1. using UnityEngine;
  2. /// <summary>
  3. /// 基础面板(基类):包含面板的状态信息,以及在派生类中要重写的函数
  4. /// </summary>
  5. public class BasePanel
  6. {
  7. /// <summary>
  8. /// 面板类型信息:外部只读,内部可写
  9. /// </summary>
  10. /// <value></value>
  11. public PanelType PanelType{get;private set;}
  12. /// <summary>
  13. /// 基础面板的构造函数
  14. /// </summary>
  15. /// <param name="panelType"></param>
  16. public BasePanel(PanelType panelType)
  17. {
  18. PanelType=panelType;
  19. Debug.Log("基类构造函数");
  20. }
  21. /// <summary>
  22. /// 打开面板时执行
  23. /// </summary>
  24. public virtual void OnEnter(){ }
  25. /// <summary>
  26. /// 停用面板时执行
  27. /// </summary>
  28. public virtual void OnPause(){ }
  29. /// <summary>
  30. /// 恢复面板时执行
  31. /// </summary>
  32. public virtual void OnResume(){ }
  33. /// <summary>
  34. /// 关闭面板时执行
  35. /// </summary>
  36. public virtual void OnExit(){ }
  37. //面板扩展工具
  38. public PanelExtensionTool panelExtensionTool {get;private set;}
  39. //初始化面板扩展工具
  40. public void Initialize(PanelExtensionTool tool)
  41. {
  42. panelExtensionTool = tool;
  43. }
  44. //面板之栈
  45. public PanelStack PanelStack { get;private set;}
  46. public void Initialize(PanelStack panelStack)
  47. {
  48. PanelStack = panelStack;
  49. }
  50. //面板管理器
  51. public PanelManager PanelManager { get;private set;}
  52. public void Initialize(PanelManager panelManager)
  53. {
  54. PanelManager = panelManager;
  55. }
  56. }

面板扩展工具

用于获取面板及其子对象上的组件,也可以为其添加组件

  1. using UnityEngine;
  2. /// <summary>
  3. /// 面板扩展工具:给当前活动面板或其子对象添加组件
  4. /// </summary>
  5. public class PanelExtensionTool
  6. {
  7. /// <summary>
  8. /// 顶层的活动面板
  9. /// </summary>
  10. GameObject topPanel;
  11. //构造函数
  12. public PanelExtensionTool(GameObject panel)
  13. {
  14. topPanel = panel;
  15. }
  16. /// <summary>
  17. /// 给当前活动面板获取或者添加一个组件
  18. /// </summary>
  19. /// <typeparam name="T">组件类型</typeparam>
  20. /// <returns>组件</returns>
  21. public T GetOrAddComponent<T>() where T:UnityEngine.Component
  22. {
  23. if(topPanel.GetComponent<T>()==null)
  24. topPanel.AddComponent<T>();
  25. return topPanel.GetComponent<T>();
  26. }
  27. /// <summary>
  28. /// 根据名称,获取指定子对象上的组件,如果没有,则为其添加
  29. /// </summary>
  30. /// <param name="name">子对象的名称</param>
  31. /// <typeparam name="T">组件类型</typeparam>
  32. /// <returns>组件</returns>
  33. public T GetOrAddComponentInChildren<T>(string name) where T:UnityEngine.Component
  34. {
  35. GameObject child = FindChildGameObject(name);
  36. if(child)
  37. {
  38. if(child.GetComponent<T>()==null)
  39. child.AddComponent<T>();
  40. return child.GetComponent<T>();
  41. }
  42. return null;
  43. }
  44. /// <summary>
  45. /// 根据名称查找顶层面板上的子对象:比如按钮
  46. /// </summary>
  47. /// <param name="name">子对象名称</param>
  48. /// <returns></returns>
  49. public GameObject FindChildGameObject(string name)
  50. {
  51. //存储顶层面板的子对象的全部组件的Transform属性
  52. Transform[] trans = topPanel.GetComponentsInChildren<Transform>();
  53. foreach (Transform item in trans)
  54. {
  55. //在transform属性数组中,找到指定名称的子对象
  56. if (item.name == name)
  57. {
  58. return item.gameObject;
  59. }
  60. }
  61. Debug.Log("找不到子对象");
  62. return null;
  63. }
  64. }

面板之栈

用于管理面板的响应顺序

打开一个面板,入栈,其父面板需要暂停响应

关闭一个面板,出栈,其父面板需要恢复响应

栈顶的面板可以交互,其余面板需要处于暂停响应的状态

  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. /// <summary>
  4. /// 面板之栈:用于管理面板的响应顺序
  5. /// </summary>
  6. public class PanelStack
  7. {
  8. /// <summary>
  9. /// 存储面板的栈
  10. /// </summary>
  11. private Stack<BasePanel> stack;
  12. /// <summary>
  13. /// 面板管理器
  14. /// </summary>
  15. private PanelManager panelManager;
  16. //面板基类引用
  17. private BasePanel panel;
  18. /// <summary>
  19. /// 初始化面板之栈
  20. /// </summary>
  21. public PanelStack()
  22. {
  23. stack = new Stack<BasePanel>();
  24. panelManager = new PanelManager();
  25. }
  26. /// <summary>
  27. /// 打开面板时将面板入栈
  28. /// </summary>
  29. /// <param name="nextPanel"></param>
  30. public void Push(BasePanel nextPanel)
  31. {
  32. //如果还有面板在显示
  33. if(stack.Count>0)
  34. {
  35. //取栈顶
  36. panel = stack.Peek();
  37. //暂停上一个面板
  38. panel.OnPause();
  39. }
  40. //新面板入栈
  41. stack.Push(nextPanel);
  42. //获取一个面板
  43. GameObject panelToShow = panelManager.ShowPanel(nextPanel.PanelType);
  44. //初始化面板的工具
  45. nextPanel.Initialize(new PanelExtensionTool(panelToShow));
  46. //初始化面板的面板顺序管理器
  47. nextPanel.Initialize(this);
  48. //初始化面板管理器
  49. nextPanel.Initialize(panelManager);
  50. //面板进入时要执行的任务
  51. nextPanel.OnEnter();
  52. }
  53. /// <summary>
  54. /// 关闭面板时将面板出栈:弹出栈顶的面板,再恢复新栈顶的面板
  55. /// </summary>
  56. public void Pop()
  57. {
  58. if(stack.Count>0)
  59. {
  60. stack.Pop().OnExit();
  61. //栈顶的面板退出
  62. //stack.Peek().OnExit();
  63. //面板出栈
  64. //stack.Pop();
  65. }
  66. //恢复下层面板
  67. if(stack.Count>0)
  68. stack.Peek().OnResume();
  69. }
  70. /// <summary>
  71. /// 关闭所有面板并执行其退出函数
  72. /// </summary>
  73. public void PopAll()
  74. {
  75. while (stack.Count > 0)
  76. stack.Pop().OnExit();
  77. }
  78. }

面板管理器

用于创建或销毁面板,并存储打开的面板的信息

  1. using System.Collections.Generic;
  2. using UnityEngine;
  3. /// <summary>
  4. /// 面板管理器:创建或销毁面板,并存储打开的面板的信息
  5. /// </summary>
  6. public class PanelManager
  7. {
  8. /// <summary>
  9. /// 用字典存储所有打开的面板,每一个面板类对应一个面板
  10. /// </summary>
  11. private Dictionary<PanelType,GameObject> panelDict;
  12. /// <summary>
  13. /// 构造函数:初始化字典
  14. /// </summary>
  15. public PanelManager()
  16. {
  17. panelDict = new Dictionary<PanelType, GameObject>();
  18. }
  19. /// <summary>
  20. /// 显示一个面板
  21. /// </summary>
  22. /// <param name="type">UI类型</param>
  23. /// <returns></returns>
  24. public GameObject ShowPanel(PanelType type)
  25. {
  26. //将画布指定为面板的父对象
  27. GameObject parent=GameObject.Find("Canvas");
  28. if(!parent)
  29. {
  30. UnityEngine.Debug.Log("Error:画布不存在");
  31. return null;
  32. }
  33. //如果字典中有指定的面板的信息,则返回这个面板的对象
  34. if(panelDict.ContainsKey(type))
  35. return panelDict[type];
  36. //将指定的面板克隆到画布上
  37. GameObject panel = GameObject.Instantiate(Resources.Load<GameObject>(type.Path),parent.transform);
  38. //设定面板对象的名字
  39. panel.name=type.Name;
  40. //加入字典
  41. panelDict.Add(type,panel);
  42. return panel;
  43. }
  44. /// <summary>
  45. /// 关闭一个面板
  46. /// </summary>
  47. public void DestroyPanel(PanelType type)
  48. {
  49. if(panelDict.ContainsKey(type))
  50. {
  51. //销毁指定的面板
  52. Object.Destroy(panelDict[type]);
  53. //从字典移除该面板的键值对
  54. panelDict.Remove(type);
  55. }
  56. }
  57. }

场景管理

游戏管理器

用于加载初始场景

保存场景管理系统的引用,通过提供单例,让其他脚本可以获取到场景管理系统

  1. using UnityEngine;
  2. public class GameManager : MonoBehaviour
  3. {
  4. //单例模式:外部可以通过这个实例,调用场景管理系统内的函数
  5. public static GameManager instance{get;private set;}
  6. //场景管理系统
  7. public SceneSystem sceneSystem{get;private set;}
  8. private void Awake()
  9. {
  10. //如果单例还没有实例化,则赋值。如果已经实例化,则销毁自身。
  11. if (instance == null)
  12. instance = this;
  13. else
  14. Destroy(gameObject);
  15. sceneSystem = new SceneSystem();
  16. //将单例放入DontDestroyOnLoad,确保切换场景之后不会丢失,可以继续使用
  17. DontDestroyOnLoad(gameObject);
  18. }
  19. private void Start()
  20. {
  21. //打开初始场景
  22. sceneSystem.SetScene(new StartScene());
  23. }
  24. }

场景基类

将场景基类写为抽象类,用于给具体的场景继承,必须实现它的两个虚函数

  1. public abstract class SceneBase
  2. {
  3. //场景进入时要执行的操作
  4. public abstract void OnEnter();
  5. //场景退出时要执行的操作
  6. public abstract void OnExit();
  7. }

场景管理系统

用于加载和退出场景

  1. //场景的状态管理系统
  2. public class SceneSystem
  3. {
  4. //场景基类
  5. SceneBase sceneBase;
  6. //设置场景:退出前一个场景,加载后一个场景
  7. public void SetScene(SceneBase scene)
  8. {
  9. sceneBase?.OnExit();
  10. sceneBase = scene;
  11. sceneBase?.OnEnter();
  12. }
  13. }

初始场景

场景继承场景基类,并实现其中状态转换时需要执行的两个函数:进入、退出

如果进入时,当前场景已加载,则显示要展示的面板

如果进入时没有加载场景,则加载场景

使用事件函数(委托)对场景的加载进行监听

事件函数SceneLoad的第一个参数Scene是场景,第二个参数是加载模式

无需手动为其赋值,只需要将事件函数绑定到SceneManager.sceneLoaded即可

SceneManager.sceneLoaded += SceneLoaded;

如果监听到场景加载,Scene变化吗,则执行SceneLoaded函数,用于执行加载面板等操作

  1. using UnityEngine.SceneManagement;
  2. public class StartScene:SceneBase
  3. {
  4. //场景名
  5. readonly string sceneName="StartScene";
  6. //场景顺序管理器
  7. PanelStack panelStack;
  8. public override void OnEnter()
  9. {
  10. panelStack = new PanelStack();
  11. //当前的活动场景不是指定的场景,就加载指定的场景
  12. if(SceneManager.GetActiveScene().name!=sceneName)
  13. {
  14. SceneManager.LoadScene(sceneName);
  15. SceneManager.sceneLoaded+=SceneLoaded;
  16. }
  17. //如果是指定的场景,那么就显示要显示的面板
  18. else panelStack.Push(new StartPanel());
  19. }
  20. public override void OnExit()
  21. {
  22. //如果不取消绑定,该函数将被重复绑定,监听到场景加载时,会被错误地重复执行多次
  23. SceneManager.sceneLoaded-=SceneLoaded;
  24. }
  25. /// <summary>
  26. /// 场景加载完毕后执行的方法
  27. /// </summary>
  28. /// <param name="scene"></param>
  29. /// <param name="load"></param>
  30. private void SceneLoaded(Scene scene,LoadSceneMode load)
  31. {
  32. // 显示初始面板
  33. panelStack.Push(new StartPanel());
  34. }
  35. }

主场景

与初始场景类似

  1. using UnityEngine.SceneManagement;
  2. public class MainScene : SceneBase
  3. {
  4. //场景名
  5. readonly string sceneName="MainScene";
  6. //面板栈
  7. PanelStack panelStack;
  8. public override void OnEnter()
  9. {
  10. panelStack = new PanelStack();
  11. if(SceneManager.GetActiveScene().name!=sceneName)
  12. {
  13. SceneManager.LoadScene(sceneName);
  14. SceneManager.sceneLoaded += SceneLoaded;
  15. }
  16. else panelStack.Push(new MainPanel());
  17. }
  18. public override void OnExit()
  19. {
  20. SceneManager.sceneLoaded -= SceneLoaded;
  21. }
  22. void SceneLoaded(Scene scene,LoadSceneMode load)
  23. {
  24. panelStack.Push(new MainPanel());
  25. }
  26. }

主场景中的面板

仅仅用于测试能否从主场景返回初始场景

  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. //主面板
  4. public class MainPanel : BasePanel
  5. {
  6. static readonly string path = "Prefabs/MainPanel";
  7. public MainPanel() : base(new PanelType(path)){}
  8. public override void OnEnter()
  9. {
  10. panelExtensionTool.GetOrAddComponentInChildren<Button>("Exit").onClick.AddListener(() =>
  11. {
  12. //返回初始场景
  13. GameManager.instance.sceneSystem.SetScene(new StartScene());
  14. PanelStack.PopAll();
  15. }
  16. );
  17. }
  18. public override void OnExit()
  19. {
  20. PanelManager.DestroyPanel(this.PanelType);
  21. }
  22. public override void OnPause()
  23. {
  24. panelExtensionTool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = false;
  25. }
  26. public override void OnResume()
  27. {
  28. panelExtensionTool.GetOrAddComponent<CanvasGroup>().blocksRaycasts = true;
  29. }
  30. }

效果

运行前

开始场景

打开子窗口

此时无法点击主面板的按钮

关闭子窗口

主面板上的按钮又可以点击了

跳转到另一个场景

回到初始场景

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/140751
推荐阅读
相关标签
  

闽ICP备14008679号