Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Introdução ao skinning GUI

É essencial para um jogo fornecer uma interface de usuário clara, informativa e visualmente agradável aos seus jogadores. Embora os nós Control venham com um visual decentemente funcional por padrão, sempre há espaço para exclusividade e ajustes específicos para cada caso. Para esse propósito, o motor Godot inclui um sistema de customização de GUI (ou temas), que permite personalizar a aparência de cada controle em sua interface de usuário, incluindo seus controles personalizados.

Aqui está um exemplo desse sistema em ação — um jogo com a GUI radicalmente diferente do tema de UI padrão do motor:

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

Uma tela de "Gear Up!" em Tank Kings, cortesia da Winterpixel Games

Além de alcançar um visual único para o seu jogo, este sistema também permite que os desenvolvedores forneçam opções de personalização para os usuários finais, incluindo configurações de acessibilidade. Os temas de UI são aplicados de maneira cascata (ou seja, eles se propagam dos controles pais para seus filhos), o que significa que as configurações de fonte ou ajustes para usuários daltônicos podem ser aplicados em um único lugar e afetar toda a árvore de UI. É claro que esse sistema também pode ser usado para fins de gameplay: seu jogo baseado em heróis pode mudar seu estilo para o personagem do jogador selecionado, ou você pode dar características diferentes para os lados em seu projeto baseado em equipes.

O básico sobre temas

O sistema de customização é movido pelo recurso Theme. Todo projeto do Godot possui um tema padrão inerente que contém as configurações usadas pelos nós de controle integrados. É isso que dá aos controles seu visual distinto logo de início. Um tema apenas descreve a configuração, no entanto, e ainda é tarefa de cada controle individual usar essa configuração da maneira necessária para se exibir. É importante lembrar disso ao implementar seus próprios controles personalizados.

Nota

Até mesmo o próprio editor do Godot conta com o tema padrão. Mas ele não tem a mesma aparência de um projeto do Godot porque aplica seu próprio tema fortemente personalizado por cima do tema padrão. Em princípio, isso funciona exatamente como funcionaria no seu jogo, conforme explicado abaixo.

Itens do tema

A configuração que fica armazenada em um tema consiste em itens de tema. Cada item possui um nome exclusivo e deve ser um dos seguintes tipos de dados:

  • Color

    Um valor de cor, que é frequentemente usado para fontes e fundos. As cores também podem ser usadas para modulação de controles e ícones.

  • Constante

    Um valor inteiro, que pode ser usado tanto para propriedades numéricas de controles (como a separação de itens em um BoxContainer) quanto para flags booleanas (como o desenho de linhas de relacionamento em uma Tree).

  • Fonte

    Um recurso de fonte, que é usado por controles que exibem texto. As fontes contêm a maioria das configurações de renderização de texto, exceto por seu tamanho e cor. Além disso, o alinhamento e a direção do texto são controlados por controles individuais.

  • Tamanho da fonte

    Um valor inteiro, que é usado junto com uma fonte para determinar o tamanho no qual o texto deve ser exibido.

  • Icon

    Um recurso de textura, que é normalmente usado para exibir um ícone (em um Button, por exemplo).

  • StyleBox

    Um recurso StyleBox, uma coleção de opções de configuração que definem a maneira como um painel de UI deve ser exibido. Isso não se limita ao controle Panel, pois as styleboxes são usadas por muitos controles para seus fundos e sobreposições.

    Diferentes controles aplicarão StyleBoxes de uma maneira diferente. Mais notavelmente, as styleboxes de focus (foco) são desenhadas como uma sobreposição a outras styleboxes (como normal ou pressed) para permitir que a stylebox base permaneça visível. Isso significa que a stylebox de foco deve ser projetada como um contorno ou uma caixa translúcida, de modo que o fundo dela possa permanecer visível.

Tipos de temas

Para ajudar na organização de seus itens, cada tema é separado em tipos, e cada item deve pertencer a um único tipo. Em outras palavras, cada item de tema é definido por seu nome, seu tipo de dado e seu tipo de tema. Essa combinação deve ser única dentro do tema. Por exemplo, não pode haver dois itens de cor chamados font_color em um tipo chamado Label, mas pode haver outro item font_color em um tipo LineEdit.

O tema padrão do Godot vem com múltiplos tipos de tema já definidos, um para cada nó de controle integrado que usa a customização de UI. O exemplo acima contém itens de tema reais presentes no tema padrão. Você pode consultar a seção Theme Properties na referência da classe de cada controle para ver quais itens estão disponíveis para ele e suas classes filhas.

Nota

As classes filhas podem usar itens de tema definidos para sua classe pai (sendo o Button e seus derivados um bom exemplo disso). Na verdade, cada controle pode usar cada item de tema de qualquer tipo de tema, se necessário (mas para maior clareza e previsibilidade, tentamos evitar isso no motor).

É importante lembrar que, para as classes filhas, esse processo é automatizado. Sempre que um controle integrado solicita um item de tema do tema, ele pode omitir o tipo de tema, e o nome da sua classe será usado no lugar. Além disso, os nomes das classes de suas classes pais também serão usados por sua vez. Isso permite que alterações na classe pai, como Button, afetem todas as classes derivadas sem a necessidade de personalizar cada uma delas.

Você também pode definir seus próprios tipos de tema e personalizar adicionalmente tanto os controles integrados quanto os seus próprios controles. Como os controles integrados não têm conhecimento dos seus tipos de tema personalizados, você deve utilizar scripts para acessar esses itens. Todos os nós de controle possuem vários métodos que permitem buscar itens de tema do tema que está aplicado a eles. Esses métodos aceitam o tipo de tema como um dos argumentos.

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

Para dar mais oportunidades de personalização, os tipos também podem ser vinculados como variações de tipo (type variations). Este é outro caso de uso para tipos de tema personalizados. Por exemplo, un tema pode conter um tipo Header que pode ser marcado como uma variação do tipo base Label. Um controle Label individual pode então ser configurado para usar a variação Header para seu tipo e, cada vez que um item de tema for solicitado de um tema, essa variação será usada antes de qualquer outro tipo. Isso permite armazenar várias predefinições de itens de tema para a mesma classe do nó de controle em um único recurso Theme.

Aviso

Apenas as variações disponíveis no tema padrão ou definidas no tema personalizado do projeto são mostradas no painel Inspetor como opções. Você ainda pode inserir manualmente o nome de uma variação que esteja definida fora desses dois lugares, mas é recomendado manter todas as variações no tema do projeto.

Você pode aprender mais sobre a criação e o uso de variações de tipo de tema em um artigo dedicado.

Personalizando um controle

Cada nó de controle pode ser personalizado diretamente sem o uso de temas. Isso é chamado de sobreposições locais (local overrides). Cada propriedade de tema da referência de classe do controle pode ser substituída diretamente no próprio controle, usando o painel Inspetor ou scripts. Isso permite fazer alterações granulares em uma parte específica da UI, sem afetar mais nada no projeto, incluindo os filhos desse controle.

../../_images/themecheck.webp

As sobreposições locais são menos úteis para a identidade visual da sua interface de usuário, especialmente se você busca consistência. No entanto, para nós de layout, elas são essenciais. Nós como o BoxContainer e o GridContainer usam constantes de tema para definir a separação entre seus filhos, e o MarginContainer armazena suas margens personalizáveis em seus itens de tema.

Sempre que um controle possui uma sobreposição de item de tema local, esse é o valor que ele utiliza. Os valores fornecidos pelo tema são ignorados.

Personalizando um projeto

Por padrão, cada projeto adota o tema de projeto padrão fornecido pelo Godot. O tema padrão em si é constante e não pode ser alterado, mas seus itens podem ser substituídos por um tema personalizado. Os temas personalizados podem ser aplicados de duas maneiras: como uma configuração de projeto e como uma propriedade de nó em toda a árvore de nós de controle.

Existem duas configurações de projeto que podem ser ajustadas para afetar todo o seu projeto: GUI > Theme > Custom permite definir um tema personalizado para todo o projeto, e GUI > Theme > Custom Font faz o mesmo para a fonte padrão de fallback. Quando um item de tema é solicitado por um nó de controle, o tema personalizado do projeto, se presente, é verificado primeiro. Somente se ele não tiver o item, o tema padrão será verificado.

Isso permite que você configure o visual padrão de cada controle do Godot com um único recurso de tema, mas você pode ir mais a fundo do que isso. Cada nó de controle também possui uma propriedade theme, que permite definir um tema personalizado para o ramo de nós que começa a partir daquele controle. Isso significa que o controle e todos os seus filhos, e os filhos deles por sua vez, verificarão primeiro esse recurso de tema personalizado antes de recorrer ao projeto e aos temas padrão.

Nota

Em vez de alterar a configuração do projeto, você pode definir o recurso de tema personalizado no nó de controle mais raiz de toda a sua ramificação de UI para obter quase o mesmo efeito. Embora no projeto em execução ele se comporte como esperado, as cenas individuais ainda serão exibidas usando o tema padrão ao visualizá-las ou executá-las diretamente. Para corrigir isso, você pode definir o mesmo recurso de tema no controle raiz de cada cena individual.

Por exemplo, você pode ter um determinado estilo para botões no tema do seu projeto, mas desejar um visual diferente para botões dentro de um diálogo pop-up. Você pode definir um recurso de tema personalizado no controle raiz do seu pop-up e definir um estilo diferente para os botões dentro desse recurso. Desde que a cadeia de nós de controle entre a raiz do pop-up e os botões permaneça ininterrupta, esses botões usarão os estilos definidos no recurso de tema que estiver mais próximo deles. Todos os outros controles ainda serão estilizados usando o tema do projeto e os estilos do tema padrão.

Para resumir, para um controle arbitrário, sua pesquisa de item de tema seria algo assim:

  1. Verifica se há sobreposições locais do mesmo tipo de dado e nome.

  2. Usando a variação de tipo do controle, o nome da classe e os nomes das classes pais:

    1. Verifica cada controle começando por si mesmo e vê se ele possui uma propriedade de tema definida;

    2. Se possuir, verifica se esse tema tem o item correspondente do mesmo nome, dado e tipo de tema;

    3. Se não houver um tema personalizado ou se ele não tiver o item, move-se para o controle pai;

    4. Repete os passos de a a c até que a raiz da árvore seja alcançada ou um nó que não seja de controle seja alcançado.

  3. Usando a variação de tipo do controle, o nome da classe e os nomes das classes pais, verifica o tema de todo o projeto, se estiver presente.

  4. Usando a variação de tipo do controle, o nome da classe e os nomes das classes pais, verifica o tema padrão.

Mesmo que o item não exista em nenhum tema, um valor padrão correspondente para esse tipo de dados será retornado.

Além dos controles

Naturalmente, os temas são um tipo ideal de recurso para armazenar a configuração de algo visual. Embora o suporte para temas seja incorporado aos nós de controle, outros nós também podem usá-los, como qualquer outro recurso.

Um exemplo de uso de temas para algo além do controle pode ser uma modulação de sprites para as mesmas unidades em times diferentes em um jogo de estratégia. Um recurso de tema pode definir uma coleção de cores e sprites (com a ajuda de scripts) podem usar essas cores para desenhar a textura. O principal benefício é que você pode criar temas diferentes usando os mesmos itens de tema para as equipes vermelha, azul e verde e trocá-los com uma única alteração de recurso.