UMG
El sistema de interfaz de usuario de Unreal se llama Unreal Motion Graphics o UMG. Es muy diferente al sistema nGUI 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 antes con ese sistema. El diseñador se describe en detalle en la documentación oficial. Las páginas Cómo crear tu IU y Prácticas recomendadas de UMG son especialmente útiles para desarrolladores que vienen desde 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 demasiado tiempo si se hiciera de forma manual. Un ejemplo práctico es la detección de cambios de dispositivo de entrada y cambiar los íconos de entrada automáticamente en la pantalla. Hacer esto manualmente llevaría mucho tiempo, pero Common UI 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 necesitas habilitarlo en la ventana de complementos. En el menú, ve a Editar > Complementos, busca “Common UI Plugin”, habilítalo y reinicia el editor.
Ve a Ajustes del proyecto > Ajustes generales y cambia la Clase de cliente del visor del juego de “GameViewportClient” a “CommonGameViewportClient”. Esto permite que los widgets de CommonUI reciban eventos de entrada del motor.
En Configuración del proyecto > Ajustes de entrada común, marca la casilla de Habilitar compatibilidad con Enhanced Input. Esto permite que Enhanced Input funcione con CommonInput. CommonInput es lo que controla 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 es AParrotHUD. La clase HUD en Unreal Engine es un actor creado para cada jugador local que controla la vista 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 tu configuración de modo de juego. Cuando usas esta clase en Parrot, lo haces como 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 widget base en C++ para todos tus otros widgets de interfaz de usuario. En su interior, hay una lista de “capas” que son del tipo UCommonActivatableWidgetContainerBase. Todos los demás widgets que desees mostrar serán colocados en una de estas capas.
Las capas básicas que configuramos son:
Game: La capa donde colocas tu widget HUD de UMG.
GameMenu: La capa donde colocas cualquier widget que desees mostrar en la parte superior del HUD.
Menu: La capa para todos los widgets de pantalla, como pantalla de pausa, pantalla de ajustes, pantalla de inventario y otras pantallas similares.
Modal: La capa para todas las ventanas emergentes modales.
Solo hay activo un widget por capa. Puedes colocar varios widgets de pantalla en la capa “Menú”, pero solo el último estará activo y se mostrará.
En Parrot, hemos creado también 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 interfaz de usuario en Parrot.
Estilo de widgets
Con el complemento Common UI y la configuración de pantalla, puedes comenzar a estilizar tus widgets. Un buen ejemplo que puedes ver es W_ButtonBase en Content/UI/Widgets/Common. Utiliza los datos de estilo ButtonStyle_Base en Content/UI/Styling. Utiliza la clase UCommonButtonStyle de Common UI. Hay muchas opciones que puedes personalizar. Algunos ejemplos son sonidos y pinceles basados en el estado del botón. Common UI tiene muchas clases de estilo como esta, dependiendo del widget que estés utilizando. Si necesitas hacer algo personalizado, un buen lugar para buscar referencias es el código de motor para estos widgets estilizados.
Pantalla de carga
La pantalla de carga en Parrot utiliza un complemento propio de Epic Games: CommonLoadingScreen. Podemos encontrar otro ejemplo de este complemento puesto en práctica en el proyecto de muestra Lyra de Epic Games. Para comprender por qué usamos este complemento, primero debemos entender los fundamentos de la carga de nivel en Unreal Engine.
Hay algunas maneras de controlar la carga de niveles en UE. Un enfoque sencillo es 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 tiene una limitación. Cuando se invoca esta función, el mapa se carga de forma sincrónica, lo que puede provocar grandes entrecortes dependiendo de cuántos datos necesiten ser cargados para el nuevo mapa. Otro problema es que si se añade un widget al visor, quedará atado al controlador de jugador que existe en el nivel anterior. Cuando haya una transición de nivel, se borrará como parte de la descarga del nivel.
Puede ser bueno cargar un nuevo modo de juego basado en el mapa (por ejemplo, nivel de un jugador vs 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 asincrónica resuelve el problema de que los recursos no estén listos para cuando se llame a Open Level. Como se menciona, el trabajo de la pantalla de carga ya se realiza aquí. La configuración del complemento es sencilla, y puedes configurar el widget de pantalla de carga en Editar > Ajustes 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. Vale la pena explorar BP_ParrotGameInstance por tu cuenta para ver cómo hemos configurado el orden de los niveles de un solo jugador y multijugador. La configuración del estado del juego se explica en la documentación Marcos de mecánicas de juego de Unreal.