O Unity possui um bom sistema para criar uma interface de usuário do UI Canvas. Muito material de treinamento foi escrito nele, mas a maioria dos guias informa apenas quais botões pressionar e qual código gravar para fazê-lo funcionar. Como exemplos, uma pequena interface geralmente consiste em um par de janelas: o menu principal, configurações. No entanto, nos jogos há muito mais janelas e quando já existem pelo menos uma dúzia delas, surge a necessidade de algum tipo de organização. Como parte deste artigo, quero falar sobre como resolvo esse problema.
Primeiro, você precisa selecionar janelas individuais na sua interface. Por janela, quero dizer um painel com alguns controles.
Cada janela deve ter um objeto raiz que conterá todos os controles. Este objeto representará a janela como um todo. Por exemplo, há um painel no qual os controles estão localizados, é lógico tornar esses elementos filhos em relação ao painel. Um componente é anexado a cada janela, que é o descendente da classe abstrata Window.
Janela
Window é escrito com base no pressuposto de que janelas podem ter janelas filho, ou seja, aquelas janelas que podem ser abertas da janela atual ao mesmo tempo e ao mesmo tempo uma janela filho pode ser aberta e todo o resto deve ser fechado. Para esse fim, a classe contém a propriedade CurrentWindow na qual o link para a janela que está aberta no momento é armazenado. E também há um evento OnOpen que relata a abertura de uma janela. O método ChangeCurrentWindow () pode ser inscrito neste evento perto de janelas filho, para que, a qualquer momento, uma janela filho seja aberta, feche a janela filho aberta e altere o link para a janela aberta atual; abaixo, darei um exemplo de implementação. Também na classe existem os métodos SelfClose () e SelfOpen (), esses métodos são responsáveis por como a janela será aberta e fechada. No método Awake (), a janela é registrada no UIManager, ou seja, um link para a janela é adicionado.
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
Em seguida, passamos à classe UIManager, que é uma classe sigleton, para que todas as janelas possam acessá-lo, se necessário. Como você pode ver, ele possui uma lista de janelas do Windows, armazena links para todas as janelas do palco. InitUI () é necessário para inicializar algo, por exemplo, se você deseja criar janelas a partir de prefabs, então aqui você pode executar suas instâncias.
No método Start (), você pode abrir janelas que devem ser abertas desde o início ou vice-versa e fechar outras desnecessárias. O método Get () permite obter um link para uma janela específica.
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() {
Configurações
Como exemplo, darei minha implementação da janela de configurações:
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(); } }
Na janela de configurações, eu posso abrir outras 4 janelas para que apenas uma janela seja aberta, inscrevo o método ChangeCurrentWindow () da janela de configurações nos eventos OnOpen das janelas filho, para que as janelas abertas sejam fechadas quando outras abrirem. As implementações SelfOpen () e SelfClose () simplesmente ativam ou desativam a janela.
Assim, é obtido um sistema de interface do usuário facilmente extensível, não há necessidade de adicionar manualmente links para janelas no inspetor ou em outro local, para adicionar uma nova janela, basta criar a classe apropriada e herdá-la da Window. Esse sistema tem algumas desvantagens: quanto mais janelas, mais classes serão necessárias para criar e o fato de que a busca por um link para a janela ocorre através da classificação através do conjunto de links, mas, na minha opinião, essas deficiências são recompensadas.
Link do Repositório