Unity具有用于创建UI Canvas用户界面的良好系统。 上面已经写了很多培训材料,但是大多数指南只告诉您要按下哪些按钮以及编写哪些代码才能使它起作用。 例如,一个小的界面通常由一对窗口组成:主菜单,设置。 然而,在游戏中有更多的窗口,而当它们已经至少有十二个时,就需要某种类型的组织。 作为本文的一部分,我想谈谈如何解决这个问题。
首先,您需要在界面中选择单个窗口。 窗口是指带有一些控件的面板。
每个窗口应具有一个包含所有控件的根对象。 该对象将代表整个窗口。 例如,有一个控件位于其上的面板,使这些元素相对于该面板为子元素是合乎逻辑的。 每个窗口都附加了一个组件,它是抽象Window类的后代。
窗
假设窗口可以有子窗口,即 可以同时从当前窗口打开的那些窗口,可以同时打开一个子窗口,其余所有窗口都应关闭。 为此,该类包含CurrentWindow属性,其中存储了当前打开的窗口的链接。 此外,还有一个OnOpen事件报告窗口的打开。 ChangeCurrentWindow()方法可以在子窗口附近订阅此事件,以便在任何时候打开一个子窗口时,它都会关闭打开的子窗口并更改到当前打开的窗口的链接,下面我将给出一个示例实现。 该类中还有SelfClose()和SelfOpen()方法,这些方法负责窗口的打开和关闭方式。 在Awake()方法中,该窗口已在UIManager中注册,即 添加到窗口的链接。
public abstract class Window : MonoBehaviour { public bool IsOpen { get; private set; } public Window CurrentWindow { get; protected set; } = null; public delegate void OpenEventHandler(Window sender); public event OpenEventHandler OnOpen; void Awake() { UIManager.Instance.Windows.Add(this.gameObject); } public void Open() { IsOpen = true; if (OnOpen != null) OnOpen(this); SelfOpen(); } protected abstract void SelfOpen(); public void Close() { IsOpen = false; if (CurrentWindow != null) CurrentWindow.Close(); SelfClose(); } protected abstract void SelfClose(); protected void ChangeCurrentWindow(Window sender) { if (CurrentWindow != null) CurrentWindow.Close(); CurrentWindow = sender; } }
UIManager
接下来,我们转到UIManager类,它是一个sigleton类,以便所有窗口都可以在需要时访问它。 如您所见,它具有Windows窗口列表,它存储舞台上所有窗口的链接。 需要InitUI()来初始化某些内容,例如,如果您想从预制件创建窗口,则可以在此处执行其实例。
在Start()方法中,可以打开应该从一开始就打开的窗口,反之亦然,可以关闭不必要的窗口。 Get()方法允许您获取到特定窗口的链接。
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public class UIManager : MonoBehaviour { public static UIManager Instance = null; public List<GameObject> Windows; void Awake() { if (Instance == null) Instance = this; else if (Instance != this) Destroy(gameObject); InitUI(); } private void InitUI() {
设置窗口
例如,我将给出设置窗口的实现:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class SettingsWindow : Window { private VideoSettingsWindow videoSettingsWindow; private LanguageSettingsWindow languageSettingsWindow; private AudioSettingsWindow audioSettingsWindow; private ControlSettingsWindow controlSettingsWindow; public void Start() { videoSettingsWindow = UIManager.Instance.GetWindow<VideoSettingsWindow>(); languageSettingsWindow = UIManager.Instance.GetWindow<LanguageSettingsWindow>(); audioSettingsWindow = UIManager.Instance.GetWindow<AudioSettingsWindow>(); controlSettingsWindow = UIManager.Instance.GetWindow<ControlSettingsWindow>(); videoSettingsWindow.OnOpen += ChangeCurrentWindow; languageSettingsWindow.OnOpen += ChangeCurrentWindow; audioSettingsWindow.OnOpen += ChangeCurrentWindow; controlSettingsWindow.OnOpen += ChangeCurrentWindow; } protected override void SelfOpen() { this.gameObject.SetActive(true); } protected override void SelfClose() { this.gameObject.SetActive(false); } public void Apply() { } public void VideoSettings() { videoSettingsWindow.Open(); } public void LanguageSettings() { languageSettingsWindow.Open(); } public void AudioSettings() { audioSettingsWindow.Open(); } public void ControlSettings() { controlSettingsWindow.Open(); } }
从设置窗口中,我可以打开其他四个窗口,以便仅打开一个窗口,然后将设置窗口的ChangeCurrentWindow()方法签名为子窗口的OnOpen事件,以便在其他窗口打开时关闭打开的窗口。 SelfOpen()和SelfClose()实现只是激活或停用窗口。
因此,获得了一个易于扩展的UI系统,无需在检查器或其他位置手动添加到Windows的链接,也无需添加新窗口,只需创建适当的类并从Window继承它即可。 这样的系统有几个缺点,即窗口越多,就需要创建更多的类,以及通过对链接数组进行排序来进行对窗口链接的搜索的事实,但我认为这些缺点是有好处的。
资料库链接