Saltar al contenido principal

Descripción General del Sistema UI

La capa de UI de OpenMon vive en Assets/OpenMon/Core/Runtime/UI/ y está construida enteramente sobre UGUI de Unity (Canvas + RectTransform). Cada pantalla, menú y diálogo comparte dos pilares fundamentales: MenuSelector para listas/cuadrículas navegables y DialogManager para cuadros de texto modales, opciones y ventanas emergentes complejas.

Arquitectura de un Vistazo​

UI/
├── MenuSelector.cs # Clase base para TODOS los menús navegables
├── ScrollableMenuSelector.cs # MenuSelector + soporte ScrollRect
├── VirtualizedMenuSelector.cs # MenuSelector + elementos reciclados/pooled
├── MenuItem.cs # Botón individual dentro de un MenuSelector
├── VirtualizedMenuItem.cs # MenuItem que conoce su fila en un pool
├── UIElementsInstaller.cs # Instalador Zenject para fábricas de UI
├── Battle/ # HUD de combate: menú principal, menú de movimientos, selector de objetivo
├── Bags/ # Pantalla de inventario/mochila con pestañas
├── Dex/ # Pantalla completa estilo Pokédex con pestañas
├── Dialogs/ # DialogManager + menú de opciones, entrada de texto, popups
├── GameMenu/ # Menú de pausa en juego (Dex, Mons, Mochila, Mapa, etc.)
├── MainMenu/ # Pantalla de título: Nueva Partida, Continuar, Créditos
├── Monsters/ # Menú de roster de monstruos, resumen, almacenamiento
├── Options/ # Pantalla de configuración (volumen, resolución, idioma, etc.)
├── Shops/ # Interfaz de tienda comprar/vender
├── Quests/ # Pantalla de registro de misiones
├── Profile/ # Perfil del jugador / tarjeta de entrenador
├── Map/ # Superposición del mapa del mundo
└── ...

Los Dos Pilares​

MenuSelector es la clase base de la que hereda casi todo menú interactivo. Maneja:

  • Navegación Vertical u Horizontal mediante el enum Navigation.
  • Flecha de selección que se anima hacia el elemento señalado, mediante la API de tweening incluida en MCE.
  • Retroalimentación de audio al navegar y seleccionar.
  • Integración de entrada a través de la interfaz IInputReceiver y IInputManager.
  • Wrap-around — navegar más allá del último elemento vuelve al primero y viceversa.
  • Hold-to-scroll — cuando CanHoldToScrollFaster está habilitado, mantener la entrada repite la navegación a un intervalo configurable.

Existen dos variantes especializadas:

ClaseCaso de Uso
ScrollableMenuSelectorAgrega un ScrollRect que se desplaza automáticamente para mantener visible el elemento seleccionado.
VirtualizedMenuSelector<TData, TButton, TFactory>Lista con object pooling para conjuntos de datos grandes (ej. Dex, Almacenamiento). Recicla instancias de botones mientras el jugador se desplaza.

Ver la página Menús para una profundización en MenuSelector.

DialogManager — Diálogos Modales y Ventanas Emergentes Complejas​

DialogManager es un Singleton que posee cada superposición modal de UI en el juego. Gestiona:

  • Diálogos de texto básicos con animación de máquina de escribir, paneles de nombre del hablante y localización.
  • Menús de opciones (Sí/No, múltiples opciones hasta 11).
  • Pantallas completas accesibles mediante métodos estáticos: Dex, Mochila, Roster, Tienda, Opciones, Perfil, Misiones, Mapa.
  • Ventanas emergentes especializadas: panel de ganancia de XP, diálogo de reemplazo de movimiento, tutor de movimientos, popup de nuevo monstruo, diálogo de entrada de texto.
  • Notificaciones a través de un NotificationManager hijo.

DialogManager se instancia mediante el patrón de fábrica de Zenject:

// DialogManagerInstaller.cs
Container.BindFactory<DialogManager, DialogManager.Factory>()
.FromComponentInNewPrefab(Prefab);

Ver la página Diálogos para la API completa.

Inyección de Dependencias​

Todas las fábricas de UI se registran a través de dos ScriptableObjectInstallers de Zenject:

  • DialogManagerInstaller — Vincula DialogManager.Factory desde un prefab.
  • UIElementsInstaller — Vincula fábricas para botones de objeto, botones de monstruo, botones de dex, botones de movimiento, botones de misión, botones de partida guardada y más. Cada vinculación tiene alcance con .WhenInjectedInto<T>() para que se use la variante de prefab correcta por pantalla.
// Ejemplo de UIElementsInstaller
Container.BindFactory<ItemButton, ItemButton.Factory>()
.FromComponentInNewPrefab(BagItemButtonPrefab)
.AsCached()
.WhenInjectedInto<BagTab>()
.Lazy();

Controladores de Pantalla Dedicados​

Cada pantalla principal extiende MenuSelector (para navegación de cuadrícula/lista), VirtualizedMenuSelector (para listas grandes con pool) o HidableUiElement (para diseños personalizados). Todas se lanzan a través de DialogManager:

PantallaControladorClase BaseLanzada Mediante
Menú de JuegoGameMenuScreenMenuSelectorDialogManager.ShowGameMenu(...)
Roster de MonstruosMonstersMenuScreenHidableUiElementDialogManager.ShowPlayerRosterMenu(...)
Mochila / InventarioBagScreenHidableUiElementDialogManager.ShowBag(...)
DexDexScreenVirtualizedMenuSelectorDialogManager.ShowDexScreen(...)
Dex de un MonstruoSingleMonsterDexScreenHidableUiElementDialogManager.ShowSingleMonsterDexScreen(...)
TiendaShopDialogHidableUiElementDialogManager.ShowShop(...)
OpcionesOptionsScreenMenuSelectorDialogManager.ShowOptionsMenu()
PerfilProfileScreenHidableUiElementDialogManager.ShowProfileScreen(...)
MisionesQuestsScreenVirtualizedMenuSelectorDialogManager.ShowQuestsScreen(...)
Entrada de TextoTextInputDialogHidableUiElementDialogManager.RequestTextInput(...)
Tutor de MovimientosMoveTutorDialogHidableUiElementDialogManager.ShowMoveTutorDialog(...)

UI de Combate​

El HUD de combate tiene su propio conjunto de subclases de MenuSelector que NO son gestionadas por DialogManager:

ControladorClase BasePropósito
MainBattleMenuMenuSelectorSelección de Atacar / Mochila / Monstruo / Huir
BattleMoveMenuSelectorMenuSelectorSelección de movimiento durante el combate
TargetMonstersMenuSelectorMenuSelectorSelección de objetivo en combates múltiples
BattleMonstersMenuHidableUiElementCambiar monstruo durante el combate
BattleInfoPanelHidableUiElement<MoveInfoPanel>Superposición de estado detallado de combate
LastBallMenuMenuSelectorLanzamiento rápido de la última bola usada

Integración del Sistema de Entrada​

Todos los menús implementan IInputReceiver, que extiende las interfaces de acción del Nuevo Sistema de Entrada de Unity:

public interface IInputReceiver : MCEInputActions.IMainActions,
MCEInputActions.IUIActions,
MCEInputActions.ITextInputActions
{
InputType GetInputType();
void OnStateEnter();
void OnStateExit();
string GetDebugName();
}

El IInputManager mantiene una pila de receptores. Cuando un menú llama a RequestInput(), se coloca a sí mismo en la pila y se convierte en el receptor activo. Llamar a ReleaseInput() lo saca de la pila. Esto maneja naturalmente los menús anidados — abrir la Mochila desde el Menú de Juego coloca el receptor de entrada de la Mochila encima, y al cerrarlo se restaura la entrada al Menú de Juego.

Buenas Prácticas para Pantallas UI Personalizadas​

  1. Heredar de MenuSelector (o ScrollableMenuSelector / VirtualizedMenuSelector para listas grandes).
  2. Agregar componentes MenuItem a cada botón en tu menú. Establecer el transform ArrowSelectorPosition para la flecha de selección.
  3. Registrar fábricas en UIElementsInstaller si tu pantalla usa elementos pooled/virtualizados.
  4. Lanzar desde DialogManager agregando un método estático y referencia serializada, siguiendo el patrón existente.
  5. Usar [SerializeField] private para todas las referencias del inspector — nunca exponer campos como public a menos que sean parte de la API.
  6. Usar claves de localización para todo el texto visible al jugador. Los componentes LocalizedTextMeshPro y LocalizedTypeWriterTMP manejan esto automáticamente.
  7. Preferir UI Toolkit para nuevas herramientas de editor, pero mantener UGUI para la UI runtime del juego para mantener consistencia con el sistema existente.