Up to date

This page is up to date for Godot 4.2. If you still find outdated information, please open an issue.

Introducción al skinning de la interfaz gráfica de usuario (GUI)

Es esencial que un juego brinde una interfaz de usuario clara, informativa y visualmente agradable a sus jugadores. Si bien los nodos de Control vienen con un aspecto decentemente funcional desde el principio, siempre hay espacio para la originalidad y la personalización específica del caso. Para este propósito, el motor Godot incluye un sistema de "skinning" (o tematización) de la interfaz gráfica de usuario (GUI), que te permite personalizar el aspecto de cada control en tu interfaz de usuario, incluidos tus controles personalizados.

Aquí tienes un ejemplo de este sistema en acción — un juego con una interfaz gráfica de usuario (GUI) que es radicalmente diferente al tema predeterminado de la interfaz del motor:

../../_images/tank-kings-by-winterpixel-games.png

Una pantalla de "¡Prepárate!" en Tank Kings, cortesía de Winterpixel Games

Además de lograr un aspecto único para tu juego, este sistema también permite a los desarrolladores ofrecer opciones de personalización a los usuarios finales, incluidas las configuraciones de accesibilidad. Los temas de la interfaz de usuario se aplican de manera en cascada (es decir, se propagan desde los controles principales hasta sus hijos), lo que significa que las configuraciones de fuentes o ajustes para usuarios con daltonismo se pueden aplicar en un solo lugar y afectar a todo el árbol de la interfaz de usuario. Por supuesto, este sistema también se puede utilizar con fines de juego: tu juego basado en héroes puede cambiar su estilo según el personaje seleccionado, o puedes darle diferentes estilos a los bandos en tu proyecto basado en equipos.

Conceptos básicos de temas (o skins)

El sistema de temas (o skins) es gestionado por el recurso Theme. Cada proyecto de Godot tiene un tema predeterminado que contiene las configuraciones utilizadas por los nodos de control incorporados. Esto es lo que le da a los controles su apariencia distintiva de forma predeterminada. Sin embargo, un tema solo describe la configuración y aún es responsabilidad de cada control individual utilizar esa configuración de la manera que requiere para mostrarse. Esto es importante tenerlo en cuenta al implementar tus propios controles personalizados.

Nota

Incluso el propio editor de Godot depende del tema predeterminado. Pero no se ve igual que un proyecto de Godot, porque aplica su propio tema altamente personalizado sobre el tema predeterminado. En principio, esto funciona exactamente igual que en tu juego, tal como se explica a continuación.

Articulos de temas

La configuración que se almacena en un tema consiste en elementos de tema. Cada elemento tiene un nombre único y debe ser uno de los siguientes tipos de datos:

  • Color

    Un valor de color, que se utiliza comúnmente para fuentes y fondos. Los colores también se pueden utilizar para la modulación de controles e iconos.

  • Constante

    Un valor entero, que se puede utilizar tanto para propiedades numéricas de los controles (como la separación de elementos en un BoxContainer), como para indicadores booleanos (como el dibujado de líneas de relación en un Tree).

  • Fuente

    Correcto, es un valor entero que puede usarse para ajustar propiedades numéricas de los controles, como la separación entre elementos en un BoxContainer, o para activar o desactivar indicadores booleanos, como el dibujado de líneas de relación en un Tree.

  • Font size

    An integer value, which is used alongside a font to determine the size at which the text should be displayed.

  • Icon

    A texture resource, which is normally used to display an icon (on a Button, for example).

  • Caja de Estilo

    Un recurso de StyleBox <class_StyleBox, una colección de opciones de configuración que define la forma en que se debe mostrar un panel de la interfaz de usuario. Esto no se limita al control Panel, ya que las cajas de estilo se utilizan en muchos controles para sus fondos y superposiciones.

Tipos de temas

Para ayudar con la organización de sus elementos, cada tema se divide en tipos, y cada elemento debe pertenecer a un solo tipo. En otras palabras, cada elemento del tema está definido por su nombre, su tipo de datos y su tipo de tema. Esta combinación debe ser única dentro del tema. Por ejemplo, no puede haber dos elementos de color con el nombre font_color en un tipo llamado Label, pero puede haber otro elemento font_color en un tipo LineEdit.

El tema predeterminado de Godot viene con varios tipos de tema ya definidos, uno para cada nodo de control incorporado que utiliza el skinning de la interfaz de usuario. El ejemplo anterior contiene elementos de tema reales presentes en el tema predeterminado. Puedes consultar la sección Propiedades del tema en la referencia de clase de cada control para ver qué elementos están disponibles para él y sus clases secundarias.

Nota

Las clases secundarias pueden usar los elementos del tema definidos para su clase padre (por ejemplo, Button y sus derivados). De hecho, cada control puede usar cualquier elemento del tema de cualquier tipo de tema, si es necesario (pero para tener claridad y previsibilidad, tratamos de evitar esto en el motor).

Es importante recordar que, para las clases secundarias, este proceso está automatizado. Siempre que un control incorporado solicite un elemento del tema del tema, puede omitir el tipo de tema y, en su lugar, se utilizará el nombre de su clase. Además, los nombres de las clases de sus clases padre también se utilizarán a su vez. Esto permite que los cambios en la clase padre, como Button, afecten a todas las clases derivadas sin necesidad de personalizar cada una de ellas.

También puedes definir tus propios tipos de tema y personalizar tanto los controles incorporados como tus propios controles. Debido a que los controles incorporados no tienen conocimiento de tus tipos de tema personalizados, debes utilizar scripts para acceder a esos elementos. Todos los nodos de control tienen varios métodos que permiten obtener elementos del tema que se les aplica. Esos métodos aceptan el tipo de tema como uno de los argumentos.

var accent_color = get_theme_color("accent_color", "MyType")
label.add_color_override("font_color", accent_color)

Para ofrecer más oportunidades de personalización, los tipos también pueden vincularse como variaciones de tipo. Este es otro caso de uso para los tipos de tema personalizados. Por ejemplo, un tema puede contener un tipo Encabezado que se marca como una variación del tipo base Label. Luego, un control individual de Label puede establecerse para usar la variación Encabezado para su tipo, y cada vez que se solicite un elemento del tema a partir de ese tema, se utilizará esta variación antes que cualquier otro tipo. Esto permite almacenar varias configuraciones preestablecidas de elementos de tema para la misma clase de nodo de control en el único recurso Theme.

Advertencia

Solo las variaciones disponibles en el tema predeterminado o definidas en el tema personalizado del proyecto se muestran como opciones en el panel del Inspector. Aún puedes ingresar manualmente el nombre de una variación que esté definida fuera de esos dos lugares, pero se recomienda mantener todas las variaciones en el tema del proyecto.

Puedes aprender más sobre cómo crear y usar variaciones de tipos de tema en un artículo dedicado.

Personalizando un control

Cada nodo de control se puede personalizar directamente sin necesidad de utilizar temas. Esto se conoce como anulaciones locales. Cada propiedad del tema que se encuentra en la referencia de clase del control se puede anular directamente en el propio control, utilizando tanto el panel del Inspector como scripts. Esto permite hacer cambios específicos en una parte particular de la interfaz de usuario, sin afectar a nada más en el proyecto, incluyendo los hijos de este control.

../../_images/themecheck.png

Las anulaciones locales son menos útiles para el estilo visual de la interfaz de usuario, especialmente si buscas coherencia. Sin embargo, para los nodos de diseño, son esenciales. Nodos como el BoxContainer y el GridContainer utilizan constantes del tema para definir la separación entre sus hijos, y el MarginContainer almacena sus márgenes personalizables en sus elementos de tema.

Cuando un control tiene una anulación local de un elemento de tema, ese valor es el que utiliza. Los valores proporcionados por el tema son ignorados.

Personalización de un proyecto

Por defecto, cada proyecto adopta el tema predeterminado proporcionado por Godot. El tema predeterminado en sí mismo es constante y no puede cambiarse, pero sus elementos pueden ser anulados con un tema personalizado. Los temas personalizados pueden aplicarse de dos maneras: como una configuración del proyecto y como una propiedad de nodo en todo el árbol de nodos de control.

Hay dos configuraciones del proyecto que se pueden ajustar para afectar a todo tu proyecto: gui/theme/custom te permite establecer un tema personalizado para todo el proyecto, y gui/theme/custom_font hace lo mismo para la fuente de reserva predeterminada. Cuando un nodo de control solicita un elemento de tema, primero se verifica el tema personalizado del proyecto, si está presente. Solo si no tiene el elemento, se verifica el tema predeterminado.

Esto te permite configurar el aspecto predeterminado de cada control de Godot con un solo recurso de tema, pero puedes ser más detallado que eso. Cada nodo de control también tiene una propiedad de theme, que te permite establecer un tema personalizado para la rama de nodos que comienza con ese control. Esto significa que el control y todos sus hijos, y sus hijos a su vez, primero verificarán ese recurso de tema personalizado antes de recurrir a los temas del proyecto y predeterminados.

Nota

En lugar de cambiar la configuración del proyecto, puedes establecer el recurso de tema personalizado en el nodo de control raíz de toda la rama de tu interfaz de usuario para lograr casi el mismo efecto. Mientras se ejecuta el proyecto, se comportará como se espera; sin embargo, las escenas individuales seguirán mostrarse utilizando el tema predeterminado al previsualizarlas o ejecutarlas directamente. Para solucionarlo, puedes establecer el mismo recurso de tema en el nodo de control raíz de cada escena individual.

Por ejemplo, puedes tener un cierto estilo para los botones en el tema de tu proyecto, pero deseas una apariencia diferente para los botones dentro de un diálogo emergente (popup dialog). Puedes establecer un recurso de tema personalizado en el control raíz (root) del diálogo emergente y definir un estilo diferente para los botones dentro de ese recurso. Mientras la cadena de nodos de control entre la raíz del diálogo emergente y los botones no se interrumpa, esos botones utilizarán los estilos definidos en el recurso de tema que esté más cercano a ellos. Todos los demás controles seguirán utilizando el tema del proyecto y los estilos de tema predeterminados.

Para resumirlo, para un control arbitrario, la búsqueda de elementos de tema se vería algo así:

  1. Verifica las anulaciones locales del mismo tipo de dato y nombre.

  2. Using control's type variation, class name and parent class names:

    1. Verifica cada control comenzando por sí mismo y verifica si tiene una propiedad de tema establecida;

    2. Si lo tiene, verifica ese tema en busca del elemento coincidente con el mismo nombre, dato y tipo de tema;

    3. Si no hay un tema personalizado o no tiene el elemento, avanza al control padre;

    4. Repite los pasos a-c hasta que se llegue a la raíz del árbol, o hasta que se alcance un nodo que no sea un control.

  3. Using control's type variation, class name and parent class names check the project-wide theme, if it's present.

  4. Using control's type variation, class name and parent class names check the default theme.

Incluso si el elemento no existe en ningún tema, se devolverá un valor predeterminado correspondiente para ese tipo de dato.

Mas allá de los controles

Naturalmente, los temas son un tipo ideal de recurso para almacenar configuraciones visuales. Aunque el soporte para la personalización de temas está integrado en los nodos de control, otros nodos también pueden utilizarlos, al igual que cualquier otro recurso.

Un ejemplo de utilizar temas para algo más allá de los controles podría ser la modulación de sprites para las mismas unidades en diferentes equipos en un juego de estrategia. Un recurso de tema podría definir una colección de colores, y los sprites (con ayuda de scripts) podrían utilizar esos colores para dibujar la textura. El principal beneficio sería que podrías crear diferentes temas utilizando los mismos elementos de tema para los equipos rojo, azul y verde, y cambiarlos con un solo cambio en el recurso.