Qué es UMG y cómo se relaciona con el gameplay
UMG (Unreal Motion Graphics) es el sistema de Unreal Engine para crear interfaces de usuario mediante Widgets. Un Widget es un Blueprint (Widget Blueprint) que define una jerarquía visual (paneles, textos, imágenes, barras) y una lógica asociada (funciones, eventos, animaciones). En gameplay, el objetivo es que el UI refleje el estado del juego (salud, inventario, interacción) de forma correcta y eficiente.
Hay dos formas comunes de “conectar” datos del juego al UI:
- Bindings (funciones que se evalúan para devolver un valor al UI). Son cómodos, pero pueden ejecutarse con frecuencia y afectar rendimiento si se abusa.
- Actualización por evento (recomendado): el gameplay emite cambios (por ejemplo, “salud cambió”) y el widget actualiza solo cuando hace falta.
Creación de Widgets en UMG: estructura y jerarquía de paneles
Widget Blueprint: Designer vs Graph
En un Widget Blueprint trabajarás principalmente en dos pestañas:
- Designer: construyes la interfaz arrastrando controles (Text, Progress Bar, Image) y organizándolos en paneles (Canvas Panel, Vertical Box, Horizontal Box, Overlay, etc.).
- Graph: defines la lógica: inicialización, funciones para actualizar textos/barras, y eventos personalizados.
Paneles típicos y cuándo usarlos
- Canvas Panel: útil para posicionamiento libre (anclas, offsets). Ideal para un HUD.
- Overlay: apila elementos uno encima de otro (por ejemplo, un fondo y encima el texto).
- Vertical Box / Horizontal Box: distribución automática en columna/fila (contadores, listas).
- Size Box: fuerza tamaño fijo o mínimo/máximo (útil para barras).
Controles básicos del capítulo
- Text: para contador de objetos y mensajes contextuales.
- Progress Bar: para salud (Percent entre 0 y 1).
- Border / Image (opcional): para mejorar legibilidad del HUD.
Práctica guiada: HUD con barra de salud, contador y mensaje de interacción
Vas a construir un HUD que muestre: (1) barra de salud, (2) contador de objetos recogidos, (3) mensaje contextual “Pulsa E para interactuar” que aparece solo cuando corresponde.
Paso 1: Crear el Widget Blueprint del HUD
1) En el Content Browser: Add > User Interface > Widget Blueprint. Nómbralo WBP_HUD.
- Escuche el audio con la pantalla apagada.
- Obtenga un certificado al finalizar.
- ¡Más de 5000 cursos para que explores!
Descargar la aplicación
2) Abre WBP_HUD en Designer. Asegúrate de tener un Canvas Panel como raíz.
3) Barra de salud:
- Arrastra un Progress Bar al Canvas.
- En Anchors, ancla arriba-izquierda (o donde prefieras).
- Ajusta tamaño (por ejemplo 300x20) y posición.
- En el panel Details, marca Is Variable para poder referenciarla desde el Graph. Renómbrala a
PB_Health.
4) Contador de objetos:
- Arrastra un Text al Canvas.
- Colócalo cerca de la barra o en otra esquina.
- Marca Is Variable y renómbralo a
TXT_Items. - Texto inicial sugerido:
Items: 0.
5) Mensaje contextual de interacción:
- Arrastra un Text al Canvas, céntralo abajo o cerca del retículo.
- Marca Is Variable y renómbralo a
TXT_Interact. - Texto sugerido:
Pulsa E para interactuar. - En Details > Visibility, ponlo inicialmente en Hidden (o Collapsed si quieres que no ocupe espacio en layouts).
Paso 2: Definir una API del widget (funciones/eventos para actualizar)
En el Graph de WBP_HUD, crea funciones simples para actualizar el UI por evento. Esto evita bindings costosos.
Función 1: SetHealthPercent
- Crea una función llamada
SetHealthPercent. - Input:
HealthPercent(Float). - En el cuerpo:
PB_Health> Set Percent conHealthPercent.
Función 2: SetItemCount
- Crea una función
SetItemCount. - Input:
Count(Integer). - Construye el texto: por ejemplo con Format Text usando
Items: {0}y conectandoCount. - Luego
TXT_Items> SetText.
Función 3: SetInteractPromptVisible
- Crea una función
SetInteractPromptVisible. - Inputs:
bVisible(Boolean) y opcionalMessage(Text) si quieres variar el mensaje. - Si incluyes
Message, primeroTXT_Interact> SetText. - Luego
TXT_Interact> SetVisibility a Visible sibVisiblees true, si no a Hidden o Collapsed.
Paso 3: Instanciar el widget y añadirlo al Viewport
El HUD normalmente se crea al inicio para el jugador local. Dos ubicaciones comunes: Player Controller o Character. En proyectos con UI, el Player Controller suele ser un buen lugar por responsabilidad (gestiona input/UI), pero también es válido desde el Character si tu arquitectura es simple.
Opción recomendada: desde el Player Controller
- En tu Blueprint de Player Controller (por ejemplo
BP_PlayerController), crea una variable:HUDWidgetde tipoWBP_HUD(Object Reference). - En Event BeginPlay:
Create Widget (Class = WBP_HUD, Owning Player = Self) -> Promote to variable HUDWidget -> Add to ViewportNotas importantes:
- Conecta Owning Player al Player Controller para que el widget tenga contexto del jugador local.
- Guarda la referencia en
HUDWidgetpara poder actualizarlo luego sin buscarlo.
Gestión de visibilidad del HUD completo
- Para ocultar/mostrar todo el HUD:
HUDWidget> Set Visibility (Visible/Hidden/Collapsed). - Si vas a alternar menús, también puedes usar Remove from Parent para destruirlo visualmente, pero entonces deberás recrearlo o conservar referencia y reañadirlo.
Paso 4: Mantener referencias seguras y evitar errores comunes
Para actualizar el UI desde gameplay necesitas una referencia válida al widget. Reglas prácticas:
- Guarda la referencia al crear el widget (variable
HUDWidget). - Valida antes de usar: usa Is Valid sobre
HUDWidgetantes de llamar funciones (especialmente si el widget puede ser removido). - No uses Get All Widgets Of Class para actualizar cada vez: es más lento y propenso a errores.
- Si el widget se crea en el Player Controller, otros Blueprints pueden acceder a él obteniendo el Controller y casteando (o mejor, exponiendo una función en el Controller que actualice el HUD).
Conectar datos del juego al UI: bindings vs eventos (rendimiento)
Bindings controlados (cuándo usarlos)
Un binding típico es enlazar el Percent de la Progress Bar a una función GetHealthPercent() en el widget. Ventajas: rapidez de implementación. Desventajas: puede evaluarse repetidamente y escalar mal si tienes muchos elementos.
Si decides usar bindings, mantenlos simples (sin casts repetidos, sin búsquedas globales). Una estrategia “controlada” es cachear referencias en Event Construct del widget (por ejemplo, guardar referencia al Character) y que el binding solo lea variables ya disponibles.
Actualización por evento (recomendado)
La idea es: cuando cambie la salud, el gameplay llama a HUDWidget.SetHealthPercent. Cuando recojas un objeto, llama a HUDWidget.SetItemCount. Cuando entres/salgas de un área interactuable, llama a HUDWidget.SetInteractPromptVisible.
Esto reduce trabajo por frame y hace más predecible el rendimiento.
Implementación práctica de eventos: salud, objetos e interacción
1) Salud: actualizar la barra cuando cambie
Supón que tu personaje tiene variables CurrentHealth y MaxHealth. Cada vez que recibas daño o curación:
- Calcula
HealthPercent = CurrentHealth / MaxHealth(Float). - Obtén el Player Controller (si el HUD vive allí) y llama a una función que actualice el HUD.
Patrón recomendado: crear en el Player Controller una función UpdateHealthUI(Current, Max) que internamente haga:
IsValid(HUDWidget) -> HUDWidget.SetHealthPercent(Current / Max)Así el Character no necesita conocer detalles del widget, solo “pide” al Controller que actualice UI.
2) Contador de objetos: actualizar al recoger
Cuando el jugador recoja un objeto (por ejemplo, en el evento de interacción o al solapar con un pickup):
- Incrementa tu variable
ItemsCollected. - Llama a
HUDWidget.SetItemCount(ItemsCollected)(idealmente a través del Player Controller).
Si tu contador depende de un sistema de inventario, la idea es la misma: el evento “añadido al inventario” dispara la actualización del texto.
3) Mensaje contextual: mostrar/ocultar según posibilidad de interactuar
El mensaje contextual debe aparecer solo cuando el jugador esté cerca de algo interactuable y tenga sentido mostrarlo.
- Cuando detectes que el jugador puede interactuar (por ejemplo, al entrar en un trigger del objeto interactuable): llama
SetInteractPromptVisible(true, "Pulsa E para interactuar"). - Cuando deje de poder interactuar (salir del trigger o perder foco): llama
SetInteractPromptVisible(false).
Recomendación: si tienes distintos tipos de interacción, pasa un Message variable (por ejemplo: “Abrir”, “Recoger”, “Hablar”) para reutilizar el mismo widget.
Gestión de visibilidad y estados del UI
Hidden vs Collapsed
- Hidden: no se ve, pero sigue ocupando espacio en layouts (útil si quieres mantener el hueco).
- Collapsed: no se ve y no ocupa espacio (útil en listas o cajas).
Para el mensaje contextual en un Canvas, cualquiera funciona; para layouts automáticos (Vertical Box), Collapsed suele ser más limpio.
Mostrar/ocultar HUD completo (por ejemplo, al abrir un menú)
Si más adelante añades un menú, puedes ocultar el HUD sin destruirlo:
HUDWidget> Set Visibility = Hidden- Al cerrar el menú: Set Visibility = Visible
Esto mantiene referencias y evita recreación constante.
Checklist de depuración rápida
| Problema | Causa típica | Solución |
|---|---|---|
| No aparece el HUD | No se ejecutó Add to Viewport o se creó en el lugar equivocado | Verifica BeginPlay del Player Controller y que el Pawn use ese Controller |
| La barra no cambia | No se llama a SetHealthPercent o el Percent no está entre 0 y 1 | Clampa el valor y confirma que el evento de daño/curación llama a la actualización |
| Acceso a None al actualizar | Referencia del widget nula o removida | Guardar referencia al crear y usar Is Valid antes de llamar |
| UI lento | Bindings complejos o demasiados | Pasar a actualización por evento y cachear referencias |