UMG
El sistema de interfaz de usuario de Unreal se llama Unreal Motion Graphics o UMG. Es muy diferente del sistema uGUI estándar de Unity. La herramienta de diseñador de IU de UMG es muy similar al constructor de interfaces UI Toolkit de Unity, si ya has trabajado con ese sistema anteriormente. El diseñador se describe detalladamente en la documentación oficial; las páginas Cómo crear tu interfaz de usuario y Prácticas recomendadas de UMG son especialmente útiles para los desarrolladores que se pasan a Unity. En el núcleo de UMG se encuentran los widgets, que son una serie de funciones y jerarquías predefinidas que puedes utilizar para construir tu interfaz de usuario.
CommonUI
CommonUI es un complemento propio creado por Epic Games que utilizamos en Parrot. CommonUI configura estilos y acciones «comunes» en todos los widgets, lo que normalmente llevaría mucho tiempo configurar manualmente de forma repetida. Un ejemplo práctico sería el de detectar cambios en los dispositivos de entrada y cambiar automáticamente los iconos de entrada en la pantalla. Hacer esto manualmente llevaría mucho tiempo, pero CommonUI automatiza el proceso. CommonUI también es necesario para la compatibilidad con la reasignación de teclas de entrada mejorada, que se describe con más detalle en la documentación de Enhanced Input.
Para configurar CommonUI, primero debes habilitarlo en la ventana Complementos. En el menú, ve a Editar > Complementos, busca «Common UI Plugin», actívalo y luego reinicia el editor.
Ve a Configuración del proyecto > Ajustes generales y cambia la Clase de cliente del visor del juego de «GameViewportClient» a «CommonGameViewportClient». Esto hace posible que los widgets CommonUI reciban eventos de entrada del motor.
En Configuración del proyecto > Configuración de entrada común, marca la casilla Habilitar compatibilidad de Enhanced Input. Esto permite que Enhanced Input funcione con CommonInput. CommonInput es lo que gestiona la entrada dentro de los widgets CommonUI.
Por último, debes habilitar algunos módulos en tu proyecto para poder utilizarlos en el código. Ve al archivo
$ProjectName.Build.cs, en este caso es el archivoParrot.Build.cs. Añade lo siguiente a la lista de PublicDependencyModuleNames:CommonInputCommonUIEnhancedInputGameplayTagsUMG
Jerarquía de widgets específicos de Parrot
La primera clase de interfaz de usuario que hay que examinar en Parrot es AParrotHUD. La clase HUD en Unreal Engine es un actor creado para cada jugador local y se encarga de la visualización frontal. Cuenta con un lienzo y un lienzo de depuración en los que se puede dibujar directamente. También puedes asignarlo como parte de la configuración del modo de juego. Cuando utilizas esta clase en Parrot, lo haces como un actor que posee el widget raíz desde el que se crean y gestionan todos tus widgets.
El tipo de clase para este widget propietario es UParrotGameLayout. UParrotGameLayout es el contenedor de widgets base en C++ para todos los demás widgets de la interfaz de usuario. En su interior, hay una lista de «capas» que son de tipo UCommonActivatableWidgetContainerBase. Todos los demás widgets que quieras mostrar se colocarán en una de estas capas.
Las capas básicas que configuramos son las siguientes:
Game: la capa en la que se coloca el widget HUD de UMG.
GameMenu: la capa en la que colocas cualquier widget que quieras mostrar en la parte superior del HUD.
Menu: la capa para todos los widgets de pantalla, como la pantalla de pausa, la pantalla de configuración, la pantalla de inventario y otras pantallas similares.
Modal: la capa para todas las ventanas emergentes modales.
Solo hay un widget activo por capa. Puedes colocar varios widgets de pantalla diferentes en la capa «Menú», pero solo el último estará activo y se mostrará.
En Parrot, también hemos creado una jerarquía de clases para pantallas activables, ya que todos esos widgets comparten una funcionalidad común y se envían a la capa Menú. La jerarquía de clases es la siguiente:
Con esta configuración creamos todas las pantallas de la interfaz de usuario en Parrot.
Estilo de widgets
Con el complemento CommonUI y la configuración de la pantalla, puedes empezar a diseñar tus widgets. W_ButtonBase en Content/UI/Widgets/Common es un buen ejemplo a seguir. Utiliza los datos de estilo ButtonStyle_Base de Content/UI/Styling. Utiliza la clase UCommonButtonStyle de CommonUI. Hay muchas opciones que puedes personalizar: por ejemplo, los sonidos y los pinceles basados en el estado del botón. CommonUI tiene muchas clases de estilos diferentes como esta, dependiendo del widget que estés utilizando. Si necesitas hacer algo personalizado, el código del motor de estos widgets con estilo es un buen lugar en el que buscar referencias.
Pantalla de carga
La pantalla de carga de Parrot utiliza un complemento propio de Epic Games: CommonLoadingScreen. Otro ejemplo práctico de este complemento se encuentra en el proyecto de ejemplo Lyra de Epic Games. Para entender por qué utilizamos este complemento, primero debemos comprender los conceptos básicos de la carga de niveles en Unreal Engine.
Hay varias formas de gestionar la carga de niveles en UE. Un enfoque sencillo consiste en llamar al nodo Open Level en un blueprint. Esta función puede cargar un mapa mediante una cadena o una referencia parcial a un objeto. Esto funciona bien para mapas sencillos, pero hay una salvedad. Cuando se invoca esta función, el mapa se carga de forma sincrónica, lo que puede provocar microcortes notables dependiendo de la cantidad de datos que sean necesarios cargar para el nuevo mapa. Otro problema aquí es que un widget añadido al visor quedará vinculado a un controlador de jugador que existe en el nivel anterior. Cuando se cambia de nivel, se limpia como parte de la descarga del nivel.
Puede resultar útil cargar un nuevo modo de juego basado en el mapa (por ejemplo, un nivel para un solo jugador frente a un nivel multijugador). Pero, ¿cómo se mantiene la pantalla de carga y se evita el posible problema de carga con Open Level? Echemos un vistazo a BP_ParrotGameInstance:
Cargar el nivel de forma asíncrona aquí resuelve el problema de que los recursos no estén listos cuando se llama a Open Level. Como menciona el comentario, el trabajo de la pantalla de carga ya se ha realizado aquí también. La configuración del complemento es sencilla y puedes establecer el widget de la pantalla de carga desde Editar > Configuración del proyecto > Pantalla de carga común.
Presta también atención a los botones de depuración que hay aquí. Probar estas funciones en el editor te dará una idea más clara del rendimiento de la pantalla de carga en una versión empaquetada.
Ahora tienes niveles que se cargan con una pantalla de carga. Merece la pena explorar BP_ParrotGameInstance más a fondo por tu cuenta para ver cómo hemos configurado el orden de los niveles para un solo jugador y para varios jugadores. La configuración del estado del juego se explica en la documentación Marco de juego de Unreal para Parrot.