Organización de la interfaz en Unity con UI Canvas

Unity tiene un buen sistema para crear una interfaz de usuario de UI Canvas. Se ha escrito una gran cantidad de material de capacitación, pero la mayoría de las guías solo le dicen qué botones presionar y qué código escribir para que funcione. Como ejemplos, una interfaz pequeña generalmente consta de un par de ventanas: el menú principal, la configuración. Sin embargo, en los juegos hay muchas más ventanas y cuando ya hay al menos una docena de ellas, surge la necesidad de algún tipo de organización. Como parte de este artículo, quiero hablar sobre cómo resuelvo este problema.

Primero debe seleccionar ventanas individuales en su interfaz. Por ventana me refiero a un panel con algunos controles.

Ejemplos de ventanas






Cada ventana debe tener un objeto raíz que contendrá todos los controles. Este objeto representará la ventana como un todo. Por ejemplo, hay un panel en el que se ubican los controles, es lógico hacer que estos elementos sean secundarios con respecto al panel. Se adjunta un componente a cada ventana, que es el descendiente de la clase de ventana abstracta.

Ventana


La ventana se escribe asumiendo que las ventanas pueden tener ventanas secundarias, es decir esas ventanas que se pueden abrir desde la ventana actual al mismo tiempo y al mismo tiempo se puede abrir una ventana secundaria, y todo el resto debe cerrarse. Para este propósito, la clase contiene la propiedad CurrentWindow en la que se almacena el enlace a la ventana que está abierta actualmente. Y también hay un evento OnOpen que informa la apertura de una ventana. El método ChangeCurrentWindow () se puede suscribir a este evento cerca de ventanas secundarias, de modo que en cualquier momento se abre una ventana secundaria, cierra la ventana secundaria abierta y cambia el enlace a la ventana abierta actual, a continuación daré una implementación de ejemplo. También en la clase hay métodos SelfClose () y SelfOpen (), estos métodos son responsables de cómo se abrirá y cerrará la ventana. En el método Awake (), la ventana se registra en el UIManager, es decir. Se agrega un enlace a la ventana.

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


A continuación, pasamos a la clase UIManager, es una clase sigleton para que todas las ventanas puedan acceder a ella si es necesario. Como puede ver, tiene una lista de ventanas de Windows, almacena enlaces a todas las ventanas en el escenario. InitUI () es necesario para inicializar algo, por ejemplo, si desea crear ventanas desde prefabricados, aquí puede hacer sus instancias.
En el método Start (), puede abrir ventanas que deberían estar abiertas desde el principio, o viceversa, cerrar las que no sean necesarias. El método Get () le permite obtener un enlace a una ventana 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() { //to do } void Start() { foreach(var window in Windows) { var windowComponent = window.GetComponent<Window>(); if (windowComponent is StartWindow) windowComponent.Open(); else windowComponent.Close(); } } public Window Get<T> () where T : Window { foreach(var window in Windows) { var windowComponent = window.GetComponent<Window>(); if (windowComponent is T) return windowComponent; } return null; } } 

SettingsWindow


Como ejemplo, daré mi implementación de la ventana de configuración:

 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(); } } 

Desde la ventana de configuración, puedo abrir otras 4 ventanas para que solo una ventana esté abierta, firmo el método ChangeCurrentWindow () de la ventana de configuración a los eventos OnOpen de las ventanas secundarias, de modo que las ventanas abiertas se cierran cuando otras se abren. Las implementaciones SelfOpen () y SelfClose () simplemente activan o desactivan la ventana.

Por lo tanto, se obtiene un sistema de interfaz de usuario fácilmente extensible, no hay necesidad de agregar manualmente enlaces a ventanas en el inspector o en otro lugar; para agregar una nueva ventana, solo necesita crear la clase apropiada y heredarla de Window. Tal sistema tiene un par de desventajas, que cuantas más ventanas, más clases será necesario crear y el hecho de que la búsqueda de un enlace a la ventana se realiza clasificando la matriz de enlaces, pero en mi opinión, estas deficiencias dan resultado.

Enlace de repositorio

Source: https://habr.com/ru/post/472770/


All Articles