Palette Swap: Variações de Inimigo com a Mesma Arte
Palette swap em pixel art: prepare o sprite com rampas por região, troque cores no Aseprite com modo indexado e Replace Color e use shader na Godot.
Palette Swap: Variações de Inimigo com a Mesma Arte
Palette swap em pixel art é trocar as cores de um sprite sem mexer no desenho: o mesmo slime vira verde, vermelho, azul e dourado, cada um com uma força diferente no jogo. É uma das técnicas mais antigas e mais rentáveis para quem faz jogo sozinho, porque uma animação de 8 frames vira quatro inimigos sem desenhar nenhum pixel novo.
O truque não está na troca, que é rápida. Está em preparar o sprite para que a troca funcione. Este tutorial mostra como montar as rampas por região, trocar cores no Aseprite de dois jeitos (modo indexado e Replace Color), exportar as variações e, quando fizer sentido, deixar a troca para um shader na engine.
Palette swap pixel art: o que é e por que economiza tempo
Pense num inimigo com animação de idle (4 frames), andar (6 frames), ataque (5 frames) e morte (6 frames). São 21 frames desenhados à mão. Fazer um segundo inimigo do zero custa outros 21. Com troca de paleta, a variação custa minutos.
E a economia não é só de desenho. A troca de cor comunica regra para o jogador sem texto: o slime vermelho dá mais dano, o azul é lento, o dourado dá mais moedas. O jogador aprende o padrão no primeiro encontro e lê os próximos inimigos de relance. Variação de cor de sprite também serve para:
- Times ou jogadores num multiplayer local.
- Estados: piscar branco ao levar dano, azul quando congelado, roxo com veneno.
- Raridade de itens: a mesma espada em cinza, verde e roxo.
- Skins desbloqueáveis do personagem principal.
O limite: troca de paleta não muda silhueta. Se todos os inimigos do jogo forem o mesmo slime recolorido, o jogador percebe e cansa. Use para variações de uma mesma família, não para substituir design de inimigo novo.
Preparar o sprite com rampas por região
Antes de desenhar, decida quais partes do sprite vão poder mudar de cor. Cada uma dessas partes é uma região, e cada região precisa de uma rampa exclusiva: uma sequência de tons do escuro ao claro que nenhuma outra região usa.
Exemplo de um slime de 16x16:
| Região | Tons | Muda nas variações? |
|---|---|---|
| Corpo | 4 (sombra, base, meio-claro, brilho) | Sim |
| Olhos | 2 (pupila, branco) | Não |
| Boca | 1 | Sim, acompanha o corpo |
| Contorno | 1 | Às vezes |
Regras para a preparação funcionar:
- Nenhuma cor compartilhada entre regiões que mudam de forma independente. Se o contorno e a sombra do corpo usam o mesmo tom escuro, trocar a sombra troca o contorno junto.
- Sem anti-aliasing automático. Ferramenta com suavização cria tons intermediários que não estão na rampa e ficam com a cor antiga depois da troca. Desenhe com o lápis.
- Rampas com o mesmo número de tons. Se a rampa do corpo tem 4 tons, todas as variações têm 4. Assim a troca é sempre de 1 para 1.
- Valor parecido entre variações. O vermelho escuro da sombra deve ter claridade próxima do verde escuro original. Se não tiver, o volume do sprite muda e ele parece desenhado por outra pessoa.
Se você quer revisar como montar rampas com hue shifting, o post sobre paleta de cores para pixel art cobre isso em detalhe.
Modo indexado no Aseprite
O modo Indexed é o que torna o palette swap trivial no Aseprite. Nele, cada pixel guarda o número de uma posição da paleta, e não a cor. A documentação oficial resume: se você muda a cor na paleta, todos os pixels que usam aquela posição mudam de aparência.
Passo a passo:
- Abra o sprite e vá em Sprite > Color Mode > Indexed. Se ele estava em RGB, o Aseprite converte usando a paleta atual.
- Organize a paleta: deixe a rampa do corpo em posições seguidas (por exemplo, índices 2 a 5). Arraste as amostras na paleta para reorganizar.
- Clique duas vezes numa amostra, ou use Edit Palette (F4), e mude a cor. O sprite inteiro, em todos os frames, muda na hora.
- Ajuste os 4 tons da rampa até a variação vermelha estar boa.
- No menu da paleta (ícone de três linhas acima das amostras), use Save Palette e salve como
slime-vermelho.gpl. - Volte às cores originais e salve também
slime-verde.gpl.
A partir daí, cada variação é um arquivo de paleta. Carregar slime-azul.gpl pelo mesmo menu, com Load Palette, transforma o sprite inteiro em segundos. Para isso funcionar, todas as paletas precisam ter o mesmo número de cores e a mesma ordem.
Trocar cor com Replace Color e paletas alternativas
Se o seu sprite está em RGB, ou você precisa trocar uma cor só numa parte do desenho, use Edit > Replace Color (Shift+R):
- Escolha a cor a ser substituída e a cor nova nas duas amostras do diálogo. A documentação oficial descreve os campos com rótulos invertidos, então confira as amostras na tela antes de aplicar.
- Tolerance em 0. Qualquer valor acima pega tons vizinhos e estraga a rampa.
- Na parte de baixo, escolha All para aplicar em todas as células do sprite. Selected aplica só no que está selecionado na timeline.
- Repita para cada tom da rampa: 4 tons, 4 substituições.
Replace Color também respeita seleção. Selecione só a cabeça do personagem e a troca acontece só ali, útil para mudar a cor do cabelo sem tocar na roupa que usa um tom parecido.
Na prática, prefiro o modo indexado para variações completas e Replace Color para correções pontuais. Em outros editores: no LibreSprite o fluxo é o mesmo do Aseprite (modo indexado e Replace Color existem). No Pixelorama existe modo indexado e a troca de cor pela paleta. No Krita e no GIMP, a alternativa é selecionar por cor (Select > By Color no GIMP, ferramenta de seleção por cor semelhante no Krita) e preencher.
Exportar as variações
Para poucas variações, exporte um sprite sheet por paleta:
- Carregue
slime-verde.gpl, vá em File > Export > Export Sprite Sheet (Ctrl+E) e exporteslime-verde.png. - Carregue
slime-vermelho.gple exporteslime-vermelho.png. - Repita para cada variação. Não salve o
.asepritecom a paleta trocada, ou você perde a referência da original.
Com muitas variações, a linha de comando do Aseprite faz isso em lote. A opção --palette troca a paleta do sprite indicado antes dela, e --sheet exporta o sprite sheet:
aseprite -b slime.aseprite --palette slime-vermelho.gpl --sheet slime-vermelho.png --data slime-vermelho.json
aseprite -b slime.aseprite --palette slime-azul.gpl --sheet slime-azul.png --data slime-azul.json
Teste com um arquivo antes de rodar para a pasta inteira. O sprite precisa estar em modo Indexed para a troca de paleta recolorir os pixels.
Até aqui é trabalho de arte que dá para dominar sozinho em uma tarde. O desafio aparece quando você multiplica isso pelo jogo inteiro: rampas planejadas para dezenas de inimigos, variações que conversam com a paleta do cenário, exportação organizada que a engine entende sem retrabalho.
Troca de paleta por shader na engine
Quando as variações são muitas, ou a cor muda durante o jogo, vale deixar a troca para a engine. Você exporta um sprite sheet só e uma pequena imagem de paleta, e o shader troca as cores na hora de desenhar.
A imagem de paleta. No Aseprite, crie um arquivo com largura igual ao número de cores da rampa e uma linha por variação. Para o slime com 6 cores trocáveis e 4 variações: 6x5 pixels. A linha 0 tem as cores originais na mesma ordem do sprite. As linhas 1 a 4 têm as cores de cada variação. Exporte como slime-paletas.png.
Na Godot 4, crie um ShaderMaterial no Sprite2D (ou AnimatedSprite2D) com este shader:
shader_type canvas_item;
uniform sampler2D palette : filter_nearest;
uniform int color_count = 6;
uniform int variant = 1;
void fragment() {
vec4 src = texture(TEXTURE, UV);
vec3 result = src.rgb;
for (int i = 0; i < color_count; i++) {
vec3 original = texelFetch(palette, ivec2(i, 0), 0).rgb;
if (distance(src.rgb, original) < 0.01) {
result = texelFetch(palette, ivec2(i, variant), 0).rgb;
break;
}
}
COLOR = vec4(result, src.a);
}
O laço compara a cor de cada pixel com a linha 0 da paleta e, quando encontra, troca pela cor da mesma coluna na linha variant. texelFetch lê o pixel exato da paleta, sem filtro. Cores que não estão na linha 0 (olhos, por exemplo) passam direto. Para mudar a variação por código, material.set_shader_parameter("variant", 2). Se vários inimigos usam o mesmo material, marque o material como Local to Scene ou duplique por instância, senão todos mudam juntos. Na textura do sprite, use filtro Nearest, que você já usa em pixel art.
Na Unity 6 com URP, o caminho é um Shader Graph do tipo Sprite Unlit. A lógica é a mesma: amostrar a textura do sprite, comparar com a primeira linha de uma textura de paleta importada com Filter Mode Point e Compression None, e devolver a cor da linha da variação. A comparação em laço fica num nó Custom Function. Cada inimigo recebe a variação por uma propriedade do material. É mais trabalho de configuração que na Godot, e para 3 ou 4 variações fixas exportar sprite sheets separados costuma ser mais simples.
Erros comuns
- Cor compartilhada entre regiões. O contorno muda junto com o corpo. Separe as cores antes de animar.
- Tolerance acima de 0 no Replace Color. Tons vizinhos da rampa são trocados juntos e o sombreamento some.
- Paletas com tamanho ou ordem diferente. Load Palette troca índice por índice. Se a ordem muda, o brilho vira sombra.
- Variação com valor muito diferente. Um amarelo claro no lugar de um verde escuro faz o sprite perder volume. Ajuste a claridade de cada tom.
- Compressão na textura. No shader, a comparação exata de cor falha se a textura for comprimida. Use sem compressão.
- Salvar o arquivo-fonte com a paleta trocada. Mantenha a paleta original no
.asepritee as variações em arquivos.gplà parte.
Próximo passo
Pegue um inimigo que você já tem, separe as rampas por região e faça três variações em modo indexado: uma mais fraca, uma mais forte e uma especial. Exporte e coloque as três na mesma tela do jogo para checar se dá para diferenciar de relance. Depois, revise o fluxo de exportação no post sobre Aseprite para jogos e o passo a passo de exportar sprite sheet do Aseprite para a Godot.
Perguntas frequentes
O que é palette swap em pixel art?
É reaproveitar o mesmo desenho trocando só as cores. Um slime verde vira um slime vermelho mais forte sem redesenhar nenhum pixel. É uma das formas mais baratas de multiplicar inimigos, itens e variações de personagem.
Como trocar a cor de um sprite no Aseprite?
O jeito mais limpo é trabalhar em modo Indexed (Sprite > Color Mode > Indexed) e editar a cor na paleta: todos os pixels que usam aquele índice mudam juntos. Em RGB, use Edit > Replace Color (Shift+R) com tolerância 0 e escopo All para afetar todos os frames.
É melhor exportar as variações ou trocar a paleta por shader?
Com 2 ou 3 variações, exportar arquivos separados é mais simples. Com muitas variações, ou quando a cor muda durante o jogo (dano, congelado, time do jogador), o shader economiza memória e trabalho de exportação.
Por que meu recolor ficou com pixels da cor antiga?
Quase sempre é cor compartilhada entre regiões ou anti-aliasing com tons intermediários. Cada região que vai trocar precisa de cores exclusivas, e o sprite não pode ter pixels de transição criados por ferramenta com suavização.