TextMeshPro na Unity: Texto, Fonte com Acento e Script
O Unity TextMeshPro é o sistema de texto padrão para UI e para texto no mundo, e no Unity 6 ele já vem dentro do pacote uGUI: você cria um texto em GameObject > UI > Text - TextMeshPro, importa os recursos essenciais uma vez e já está usando. O problema começa quando você troca a fonte padrão por uma fonte sua e o "Ação" vira "A□□o". Isso acontece porque o Font Asset gerado não tem os caracteres do português.
Aqui você vai criar um Font Asset que mostra ç, ã, õ, é e companhia, configurar fallback para nunca mais ver quadradinho, entender a diferença entre os três tipos de componente e atualizar texto por script do jeito que não gera lixo de memória a cada frame.
TextMeshPro na Unity: onde ele está no Unity 6
No Unity 6 o TextMeshPro faz parte do pacote com.unity.ugui 2.0. Não existe mais um pacote separado para instalar pelo Package Manager. O que você precisa fazer uma vez por projeto é importar os TMP Essential Resources: a fonte padrão, os shaders e o arquivo de configurações.
Dois caminhos:
- Crie o primeiro texto em GameObject > UI > Text - TextMeshPro. A Unity abre a janela TMP Importer e você clica em Import TMP Essentials.
- Ou vá em Window > TextMeshPro > Import TMP Essential Resources.
Isso cria a pasta Assets/TextMesh Pro com a fonte LiberationSans SDF e o asset TMP Settings. O mesmo menu tem Import TMP Examples & Extras, opcional, e o Font Asset Creator, que você vai usar já já.
O componente Text antigo (legado) ainda existe, mas não use em projeto novo. Ele borra em escala, não tem os recursos de material do TMP e você vai acabar migrando depois.
TextMeshPro vs TextMeshProUGUI vs TMP_Text
São três nomes que confundem no começo:
- TextMeshProUGUI: o componente que vai num objeto filho de um Canvas. É o que aparece quando você usa GameObject > UI > Text - TextMeshPro. Use para HUD, menu, diálogo.
- TextMeshPro: o componente de texto 3D, que fica no mundo como qualquer objeto, sem Canvas, desenhado por um MeshRenderer. Use para placa no cenário, nome em cima de NPC ou número de dano. Cria-se em GameObject > 3D Object > Text - TextMeshPro.
- TMP_Text: a classe base dos dois. Nos seus scripts, declare o campo como
TMP_Text. Assim o mesmo script funciona com texto de UI e texto 3D, e você não precisa reescrever nada se mudar de ideia.
Todos ficam no namespace TMPro, então o script precisa de using TMPro;.
Criando Font Asset com acentos do português
O TextMeshPro não desenha direto do arquivo .ttf ou .otf. Ele usa um Font Asset: um atlas (uma textura com todos os caracteres) gerado em SDF, o formato que mantém a letra nítida em qualquer tamanho. Se um caractere não foi para o atlas, ele não existe para o TMP.
Passo a passo com o Font Asset Creator (Window > TextMeshPro > Font Asset Creator):
- Source Font File: arraste o arquivo da sua fonte (importado em
Assets/Fonts). Antes, confira se a fonte tem acentos: abra no visualizador do sistema e procure por ç e ã. Muita fonte grátis de jogo só tem ASCII. - Sampling Point Size: deixe em Auto Sizing para começar, ou fixe em torno de 64 a 90 para uma fonte de corpo num atlas 512.
- Padding: 5 é um bom valor para atlas de 512x512. Se for usar outline grosso, suba para 8 ou 9 e aumente o atlas.
- Packing Method: Fast para testar, Optimum para o asset final.
- Atlas Resolution: 512 x 512 costuma caber o Latin-1 com folga. Se o gerador avisar que faltou espaço, vá para 1024.
- Character Set: aqui está o segredo. Escolha Unicode Range (Hex) e digite
20-7E,A0-FF. Isso cobre o ASCII imprimível mais o bloco Latin-1, que tem á, à, â, ã, é, ê, í, ó, ô, õ, ú, ç e as maiúsculas, além de º e ª. Se preferir decimal, use Custom Range com32-126,160-255. - Render Mode: SDFAA é o mais rápido de gerar e fica bom para a maioria dos casos.
- Clique em Generate Font Atlas e depois em Save. Salve com o nome da fonte e o sufixo SDF, por exemplo
Pixelify SDF.asset.
Quer gastar menos atlas? Em vez de faixa, use Custom Characters e cole só os caracteres que o jogo usa. Funciona para fonte de título, mas é arriscado em texto de diálogo: basta um tradutor usar "à" num lugar que você não previu.
Para escolher a fonte em si, legibilidade em tamanho pequeno e personalidade do jogo, o post sobre fontes para jogos e tipografia ajuda a decidir antes de gerar o atlas.
Font Asset dinâmico e fallback
Gerar o atlas na mão dá controle, mas existe um jeito mais tolerante: o Font Asset dinâmico. Selecione o arquivo da fonte no Project, clique com o botão direito e use Create > TextMeshPro > Font Asset (se aparecer um submenu de tipo, escolha SDF). O asset criado começa vazio e, com Atlas Population Mode em Dynamic (em Generation Settings no Inspector), o TMP adiciona cada caractere ao atlas na primeira vez que ele aparece na tela.
Vantagem: nunca falta caractere que exista na fonte. Custo: o arquivo da fonte vai junto na build e o atlas cresce em tempo de execução. Um meio-termo que funciona bem:
- Font Asset estático com o Latin-1 para a fonte principal, rápido e previsível.
- Um Font Asset dinâmico da mesma família (ou de uma fonte ampla) como fallback.
Para ligar o fallback, selecione o Font Asset principal e, em Fallback Font Assets, clique em + e arraste o dinâmico. Quando um caractere falta no principal, o TMP procura na lista em ordem. Existe também uma lista global de fallback no TMP Settings (em Edit > Project Settings > TextMesh Pro > Settings), que vale para todos os textos do projeto.
Até aqui é configuração de asset, e é o tipo de coisa que funciona no teste e quebra três semanas depois: o tradutor manda um texto com "à", o diálogo novo usa uma fonte que ninguém regerou, a build sai com quadradinho na tela de créditos. Num jogo inteiro, texto, UI, gameplay e build precisam conversar, e é nesse encaixe, sem alguém apontando onde olhar, que a maioria trava.
Mudando texto por script com SetText
Agora o código. O jeito direto é a propriedade text:
Arquivo PlacaDeFase.cs:
using TMPro;
using UnityEngine;
public class PlacaDeFase : MonoBehaviour
{
[SerializeField] private TMP_Text tituloTexto;
private void Start()
{
tituloTexto.text = "Fase 1: Caverna da Ação";
}
}
Para texto que muda pouco, text é perfeito. O problema é número que muda o tempo todo, tipo pontuação ou cronômetro. Escrever pontosTexto.text = "Pontos: " + pontos; todo frame cria uma string nova a cada chamada, e esse lixo vai para o coletor de memória, que de tempos em tempos causa um engasgo. O SetText com formato resolve: ele monta o texto direto no buffer interno do TMP, sem criar string.
Arquivo HudPontuacao.cs:
using TMPro;
using UnityEngine;
public class HudPontuacao : MonoBehaviour
{
[SerializeField] private TMP_Text pontosTexto;
[SerializeField] private TMP_Text tempoTexto;
private int pontos;
private float tempoDecorrido;
private int ultimoSegundoMostrado = -1;
private void Start()
{
pontosTexto.SetText("Pontos: {0}", pontos);
}
private void Update()
{
tempoDecorrido += Time.deltaTime;
int segundoAtual = Mathf.FloorToInt(tempoDecorrido);
if (segundoAtual != ultimoSegundoMostrado)
{
ultimoSegundoMostrado = segundoAtual;
tempoTexto.SetText("Tempo: {0}s", segundoAtual);
}
}
public void AdicionarPontos(int quantidade)
{
pontos += quantidade;
pontosTexto.SetText("Pontos: {0}", pontos);
}
}
Duas decisões aqui. Primeiro, SetText("Pontos: {0}", pontos) em vez de concatenar. No formato do TMP, {0:2} mostra o número com 2 casas decimais, então SetText("{0:2}", 3.14159f) vira "3.14". Segundo, o cronômetro só atualiza quando o segundo muda. Mesmo sem lixo, refazer a malha do texto 60 vezes por segundo para mostrar o mesmo número é trabalho jogado fora.
Quando o texto é de diálogo ou de interface que muda por evento, nada disso importa: use text e siga a vida. A otimização vale para o que roda em Update.
Rich text, outline e sombra
O TMP aceita tags de rich text dentro do próprio texto, sem configuração extra:
<b>negrito</b>e<i>itálico</i><color=#ED1A3B>vermelho</color>para destacar dano ou palavra-chave de diálogo<size=120%>maior</size>para enfatizar sem trocar de componente<u>sublinhado</u>e<s>riscado</s>
Outline e sombra não são tags: ficam no material do texto. Selecione o objeto de texto e, no material dele no Inspector, ligue Outline (ajuste Thickness e Color) e Underlay para sombra (ajuste Offset X, Offset Y e Dilate).
Cuidado com um detalhe: o material é compartilhado por todos os textos que usam aquele Font Asset. Ligou outline num texto, todos ganham outline. A saída é criar um Material Preset: no Inspector do texto, clique com o botão direito no cabeçalho do material e escolha Create Material Preset. Renomeie a cópia para algo como Pixelify SDF Titulo, edite e escolha esse preset no campo Material Preset do componente de texto.
Erros comuns: quadradinho no lugar do acento e texto borrado
Quadradinho no lugar do acento. O Console mostra um aviso dizendo que o caractere não foi encontrado no Font Asset nem nos fallbacks. Três causas possíveis, nesta ordem: a fonte original não tem o caractere (troque a fonte), o Font Asset foi gerado só com ASCII (regere com 20-7E,A0-FF) ou o Font Asset certo não está no texto (confira o campo Font Asset do componente).
Texto borrado ou serrilhado. Normalmente é escala. Se você aumentou o texto mexendo no Scale do Transform em vez do Font Size, o SDF até aguenta, mas a caixa fica errada e o texto pode borrar. Ajuste o Font Size. Se o texto é pixel art, use uma fonte bitmap com Render Mode RASTER e Sampling Point Size igual ao tamanho de uso, ou o SDF vai suavizar as bordas que você queria duras.
Texto que some ou corta. O Overflow está em Truncate ou a caixa do RectTransform é menor que o texto. Para teste, deixe Overflow em Overflow e veja onde o texto realmente termina.
Texto atrás do sprite no mundo 2D. O componente TextMeshPro 3D usa um MeshRenderer, que tem Sorting Layer e Order in Layer em Extra Settings. Coloque o texto numa camada acima dos sprites.
Próximo passo: texto ligado ao gameplay
Com texto nítido e com acento, o próximo exercício é ligar a UI a um valor do jogo. A barra de vida na Unity usa exatamente essa ideia: um script de vida avisa a UI por evento e a UI atualiza barra e número, sem a UI ficar perguntando o valor todo frame. E antes de espalhar texto pela tela, vale passar pelo guia de UI e UX em jogos para decidir o que o jogador realmente precisa ler durante a ação.
Perguntas frequentes
Por que o TextMeshPro mostra um quadradinho no lugar do acento?
Porque o Font Asset em uso não tem aquele caractere no atlas e nenhum fallback tem também. Gere o Font Asset incluindo a faixa Latin-1 (hex 20-7E e A0-FF) ou deixe-o em modo Dynamic, e confira a lista de Fallback Font Assets.
Qual a diferença entre TextMeshPro e TextMeshProUGUI?
TextMeshProUGUI é o componente de texto para UI, dentro de um Canvas. TextMeshPro é o componente de texto 3D, que vive no mundo como um objeto qualquer. Os dois herdam de TMP_Text, que é o tipo que você deve usar nos seus scripts.
Preciso instalar o pacote TextMeshPro no Unity 6?
Não. No Unity 6 o TextMeshPro vem dentro do pacote uGUI (com.unity.ugui 2.0). Você só precisa importar os TMP Essential Resources na primeira vez, pelo menu Window > TextMeshPro ou pelo aviso que aparece ao criar o primeiro texto.
Como mudar o texto do TextMeshPro por script?
Declare um campo [SerializeField] private TMP_Text, arraste o objeto no Inspector e use .text para textos fixos ou SetText com formato, como SetText("Pontos: {0}", pontos), para números que mudam com frequência.



