Luscofusco Studio background image

Devlog #5 – Football Legends: mi enfoque de UI Builder

En proyectos anteriores a Football Legends no había utilizado el “nuevo” sistema de creación de interfaces de Unity (UI Toolkit / UI Builder) y, siendo sincero, era bastante escéptico.

Siempre me había resultado muy intuitivo trabajar con el sistema clásico: un Canvas en la escena, dibujado sobre la cámara, con su árbol de elementos hijos, activar y desactivar objetos, configurar eventos de forma visual… Si lo has usado, ya sabes a qué me refiero: era directo y fácil de entender.

Por eso, mis primeros acercamientos a UI Builder fueron bastante confusos.
¿Qué eran exactamente los UIDocument?
¿Por qué había archivos que parecían XML y CSS?
¿Estoy creando una interfaz… o una página web? 😅

Reconozco que fui bastante testarudo. Muchos de mis miedos no tenían fundamento y estaban más relacionados con el simple hecho de cambiar de sistema.

Después de aplicarlo a este desarrollo de Football Legends puedo decir que me parece un sistema muy flexible y especialmente potente para interfaces complejas. Y sobre todose adapta excepcionalmente bien a distintos tamaños de pantalla y dispositivos, algo clave en la interfaz mobile de Football Legends.


Cómo he aprendido a trabajar con UI Builder

Mi enfoque ha sido sencillo: tomármelo con calma e ir paso a paso. Y eso es especialmente importante en un proyecto como Football Legends, donde la interfaz es el principal medio para mostrar una gran cantidad de datos.


Paso 1: Diseñar la interfaz fuera de Unity

El primer paso fue diseñar la apariencia de la interfaz en una herramienta externa a Unity. Puede parecer obvio, pero es un punto que no se debe subestimar.

Empezar a crear elementos directamente en Unity, sin una idea clara de qué necesitas, es una garantía para que el proyecto se te vaya de las manos. Tener el diseño pensado de antemano ahorra muchísimo tiempo y frustración.

En mi caso utilicé Illustrator, pero la herramienta es lo de menos. Lo importante es el planteamiento.

Un consejo que me resultó especialmente útil:
piensa en términos relativos, no en píxeles absolutos.

Por ejemplo, si necesitas un menú en la parte izquierda de la pantalla, plantéalo como un porcentaje del ancho total, no como “300 píxeles exactos”. Este enfoque facilita mucho que el diseño encaje luego en UI Builder y que se adapte correctamente a diferentes resoluciones (me hubiera encantado saber esto antes de empezar).

Para elementos pequeños como botones o iconos no siempre es viable, pero para la distribución general de zonas (menús, paneles, áreas principales) encaja muy bien con cómo funciona UI Toolkit y su sistema de contenedores anidados.


Paso 2: Construir la interfaz en UI Builder

Aquí es donde empieza el trabajo dentro de Unity, y hay varias cosas importantes que conviene tener claras desde el principio.

Atajos y ergonomía

Lo primero que recomiendo hacer, sin excepción, es asignar un atajo de teclado al UI Builder.

Ruta:
Edit → Shortcuts → Command: MainMenu / Window / UI Toolkit / UI Builder

(Busca “UI Builder” en el buscador y lo encontrarás rápido).

No preguntes, simplemente hazlo.
Yo lo asigné a F10 y listo.

Tener que abrir y cerrar el UI Builder constantemente desde los menús es muy incómodo y rompe el flujo de trabajo. Un atajo de teclado es lo ideal para esto.


Separar estructura y estilo (muy importante)

Uno de los conceptos clave de UI Builder es la separación entre estructura y apariencia visual.

El objeto base para la UI siempre es un UIDocument, que actúa como contenedor de la interfaz. Vive en un GameObject con el componente UIDocument dentro de la escena, y puedes tener uno o varios según lo que necesites.
En Football Legends opté por uno para la interfaz principal y otro para una interfaz de debug personalizada.

Al trabajar con un UIDocument aparecen dos tipos de archivos:

  • .uxml → estructura
  • .uss → estilos

El archivo .uxml define cómo está organizada la interfaz: qué elementos existen, cómo están anidados y cómo se relacionan entre sí. Aquí no deberías definir colores, fuentes ni imágenes. Este es el archivo que necesita el componente UIDocument para mostrar la UI.

Todo lo visual vive en los archivos .uss, que funcionan de forma muy similar a hojas de estilo CSS en desarrollo web. En ellos defines colores, fuentes, imágenes de fondo, animaciones (aunque no es la mejor manera creo, sigo investigando esto), etc.

Mi recomendación es clara: usa varios archivos .uss desde el principio. Separar estilos por secciones o tipos de elementos te ahorrará muchos problemas más adelante. Piénsalo bien antes de continuar, merece la pena.


Evitar el caos de los estilos inline

Este fue uno de los puntos que más confuso me resultó al principio.

Mientras modificas un elemento desde el editor visual, Unity va creando estilos inline que se insertan directamente en el archivo .uxml. Esto está bien para prototipar, pero no es demasiado claro hasta que lo entiendes.

Mi flujo de trabajo (después de rehacer los estilos unas cuantas veces 😅) es este:

  1. Añade el elemento a un contenedor existente (por ejemplo, un botón).
  2. Ajusta su aspecto desde el editor hasta que estés satisfecho.
  3. Extrae el estilo inline a un archivo .uss
    (ojo con qué .uss tengas asignado en ese momento).
  4. A partir de ese punto, no vuelvas a modificar su aspecto desde el editor visual. Abre el archivo .uss y edita el estilo allí. (Consulta la documentación oficial, está muy bien)

Desde ese momento, cualquier cambio visual debería hacerse directamente en el archivo .uss.

¿Por qué?
Porque si sigues ajustando el estilo desde el editor, acabarás con estilos repartidos entre el .uxml y el .uss para el mismo elemento. Además, los estilos definidos en el .uxml tienen prioridad, lo que puede generar comportamientos confusos y difíciles de depurar.


Organizar los estilos

Una vez extraído el estilo a un archivo .uss, merece la pena organizarlo un poco.

Cuando en el paso anterior extraes el estilo a un .uss, ten en cuenta que tendrás todos los ajustes aplicados a ese elemento en un solo estilo. Esto incluye desde colores de fuente a comportamiento en el contenedor, ¡no es lo más recomendable cuando empieza a crecer el proyecto!

Personalmente, me ha funcionado muy bien separar los estilos en dos grandes grupos:

  • Estilos de comportamiento / layout
    (tamaño, alineación, flex, posicionamiento…)
  • Estilos puramente estéticos
    (colores, fuentes, imágenes de fondo…)

Como ejemplo, actualmente utilizo cuatro archivos .uss:

  • Uno para layout general, con distribuciones tipo 33%-66%, 50%-50%, etc.
    Piensa en ello como plantillas para repartir zonas de la pantalla.
  • Otro para estructura de elementos concretos (selector de idioma, formulario, botones concretos, selector de país, etc.).
  • Un archivo para la versión oscura de la interfaz.
  • Otro archivo para la versión clara.

Esta organización me resulta muy cómoda: permite trabajar layouts completos, elementos específicos y temas visuales de forma independiente. No es del todo obligatorio, pero en interfaces extensas como la de Football Legends ayuda mucho a mantener todo bajo control.

En el caso que te interese cambiar el aspecto de la interfaz entre modo claro/oscuro sí que me parece imprescindible plantear al menos los dos archivos de cada tema por separado.


Paso 3: Programar el comportamiento de la interfaz

Dentro del flujo de desarrollo de la interfaz de Football Legends, visualmente todo está bien… pero no hace nada.

Aquí entramos en un terreno mucho más dependiente de cada proyecto, así que me limitaré a explicar el enfoque que he seguido en Football Legends, usando como ejemplo el proceso de registro de usuario.

Hay elementos que requieren programación simplemente para “hacer algo” cuando se interactúa con ellos (por ejemplo, el botón de Continuar con Google). Este tipo de elementos no suele necesitar lógica individual compleja, básicamente disparan un proceso, pero el elemento en sí no tiene un comportamiento complejo.

Pero hay otros que sí requieren un comportamiento específico. Un ejemplo es el selector de idioma.

Este selector está compuesto por:

  • Contenedor principal
  • Botón del idioma seleccionado
  • Imagen de fondo
  • Iconos de los idiomas disponibles

En la estructura .uxml queda así:

<ui:VisualElement name="language-block" picking-mode="Ignore" class="language-block">
    <ui:VisualElement name="language-button" picking-mode="Ignore" class="language-button">
        <ui:Image name="language-flag-current" picking-mode="Ignore" class="language-flag-current flag-en"/>
    </ui:VisualElement>
    <ui:VisualElement name="language-dropdown" picking-mode="Ignore" class="language-dropdown language-dropdown-image">
        <ui:Image name="es" class="flag-option flag-es"/>
        <ui:Image name="fr" class="flag-option flag-fr"/>
        <ui:Image name="de" class="flag-option flag-de"/>
        <ui:Image name="it" class="flag-option flag-it"/>
        <ui:Image name="pt" class="flag-option flag-pt"/>
        <ui:Image name="ne" class="flag-option flag-ne"/>
        <ui:Image name="jp" class="flag-option flag-jp"/>
    </ui:VisualElement>
</ui:VisualElement>

El comportamiento esperado es más complejo:

  • Al hacer clic, se despliega la lista de idiomas.
  • Al seleccionar otro idioma, se intercambian los iconos.
  • Se actualizan todas las cadenas de texto de la interfaz.
  • Se guarda la preferencia del usuario.
  • El desplegable se cierra.
  • Si se hace clic fuera, también debe cerrarse.

Esto requiere una lógica específica para ese elemento. Para ello tuve que crear un sistema independiente encargado únicamente de este comportamiento, que además se integra con el sistema de localización del juego.

No entraré aquí en detalles de implementación, pero la idea clave es esta:
cada elemento complejo de la interfaz necesita su propia programación para definir cómo se comporta.

Un detalle a tener muy en cuenta: cuidado con los picking modes de los elementos que componen la UI. Son clave para definir si un elemento es interactivo o no. Por lo que he visto, definir este comportamiento de forma explícita desde el código me ha resultado mucho más fiable.


Paso 4: Un manager central que conecta todo

En Football Legends, el último paso fue crear un manager central que actúa como conductor del proceso (en este caso, el registro de usuario).

Este manager:

  • Decide qué elementos se muestran en cada momento.
  • Escucha cambios en los distintos controles.
  • Coordina el flujo general.

Tampoco entraré en más detalles en este tema, depende totalmente de las necesidades de cada proyecto, pero quédate con la idea principal:

Este manager no se encarga del funcionamiento interno de cada elemento individual. Esa responsabilidad sigue estando en cada componente específico.


Versión en desarrollo de Football Legends, grabada desde el emulador de Android.

Conclusión final

Después de implementarlo en Football Legends, UI Builder no me parece un sistema “mágico”, ni resultó especialmente intuitivo al principio.

Una vez entendidos sus conceptos clave y adoptando una forma de trabajo ordenada, se convierte en una herramienta muy potente y bastante agradable de usar.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *