Prefab Variant na Unity: Inimigos Diferentes com Base Comum

Unity prefab variant na prática: monte inimigo base, rápido, tanque e chefe sobrescrevendo só o que muda, e saiba quando variant ganha de ScriptableObject.
Prefab Variant na Unity: Inimigos Diferentes com Base Comum
Prefab Variant na Unity é um prefab que herda de outro e guarda só o que é diferente. Você faz um inimigo base com sprite, física, colisão e script, e cria variantes "rápido", "tanque" e "chefe" que mudam velocidade, vida, tamanho e um ou outro componente. Quando você corrige o collider da base, as três recebem a correção. Esse é o uso mais comum de Unity prefab variant e é o que vamos montar aqui, no Unity 6.3 LTS.
No fim você terá uma família de quatro inimigos, vai entender o que a variante herda e o que ela sobrescreve, como isso convive com prefabs aninhados e, a parte que mais gera dúvida, quando a resposta certa não é variant e sim ScriptableObject. Se prefab ainda é novidade, comece pelo guia de prefab na Unity, que cobre Prefab Mode e overrides do zero.
O que é Prefab Variant na Unity
Pense em herança de classe, só que para objetos montados no editor. A base define tudo: hierarquia de filhos, componentes e valores. A variante aponta para a base e registra uma lista de overrides, exatamente como uma instância de prefab na cena faz. A diferença é que essa lista fica salva num asset próprio, reutilizável.
Três regras definem o comportamento:
- Campo sem override herda. Se a variante não mexeu no
Rigidbody2D, qualquer mudança noRigidbody2Dda base aparece nela. - Campo com override ignora a base. Se a variante "Tanque" definiu
maxHealth = 120, mudar a vida da base para 40 não afeta o Tanque. - Variante pode ter base que também é variante. O "Chefe" pode herdar do "Tanque", que herda da base. O manual chama isso de variante de variante e é permitido.
Visualmente, a variante aparece com o ícone de cubo azul com um lado hachurado, tanto na janela Project quanto na Hierarchy.
Criando a variante a partir do prefab base
Primeiro o inimigo base. Crie um GameObject Enemy_Base com:
- Sprite Renderer com o sprite do inimigo.
- Rigidbody2D com Gravity Scale 0 (vista de cima) ou 1 (plataforma).
- CapsuleCollider2D ajustado ao sprite.
- O script
EnemyStatsabaixo.
Arquivo EnemyStats.cs:
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class EnemyStats : MonoBehaviour
{
[SerializeField, Min(1)] private int maxHealth = 30;
[SerializeField, Min(0f)] private float moveSpeed = 2f;
[SerializeField, Min(0)] private int contactDamage = 10;
[SerializeField] private Transform target;
private Rigidbody2D rb;
private int currentHealth;
public int ContactDamage => contactDamage;
private void Awake()
{
rb = GetComponent<Rigidbody2D>();
currentHealth = maxHealth;
}
private void Start()
{
if (target == null)
{
GameObject player = GameObject.FindWithTag("Player");
if (player != null)
{
target = player.transform;
}
}
}
private void FixedUpdate()
{
if (target == null)
{
rb.linearVelocity = Vector2.zero;
return;
}
Vector2 direction = ((Vector2)target.position - rb.position).normalized;
rb.linearVelocity = direction * moveSpeed;
}
public void TakeDamage(int amount)
{
currentHealth -= amount;
if (currentHealth <= 0)
{
Destroy(gameObject);
}
}
}
O movimento usa Rigidbody2D.linearVelocity, o nome atual da propriedade no Unity 6 (tutoriais antigos usam velocity). O alvo é buscado pela tag Player no Start, porque prefab não guarda referência para objeto da cena.
Arraste Enemy_Base da Hierarchy para Assets/_Project/Prefabs/Enemies. Agora a variante: clique com o botão direito em Enemy_Base.prefab na janela Project e escolha Create > Prefab Variant. A Unity cria o arquivo na mesma pasta. Renomeie para Enemy_Fast. Repita para Enemy_Tank.
Há um segundo caminho: arrastar para a janela Project uma instância de prefab que já tem overrides na cena. A Unity pergunta se você quer um prefab original ou uma variante; escolhendo variante, os overrides daquela instância viram os overrides da variante. É útil quando você ajustou um inimigo na fase, gostou e quer transformar aquilo num tipo novo.
Overrides: o que a variante muda e o que herda
Dê duplo clique em Enemy_Fast para abrir no Prefab Mode. Repare na Hierarchy: a raiz aparece como instância da base. Tudo que você mudar aqui é gravado como override da variante, e o Inspector marca em negrito com a linha azul na margem, igual a uma instância na cena.
Para conferir o que a variante sobrescreve, selecione a raiz e abra o dropdown Overrides no bloco Prefab do Inspector. A lista mostra cada campo e componente diferente da base. Dali você pode reverter tudo ou levar as mudanças para a base. Atenção a esse segundo botão: aplicar a partir da variante muda o prefab base e, por tabela, todas as outras variantes que herdam aquele campo.
O que costuma ficar na base e o que costuma virar override:
| Fica na base (herda) | Vira override na variante |
|---|---|
| Rigidbody2D, tipo de collider, layer, tag | Valores de vida, velocidade, dano |
| Script de comportamento | Escala, cor, sprite |
| Filhos comuns (sombra, barra de vida) | Componentes extras só daquele tipo |
Exemplo: inimigo base, rápido e tanque
Com as duas variantes criadas, configure:
Enemy_Fast
EnemyStats:maxHealth12,moveSpeed4.5,contactDamage5.TransformScale 0.7.Sprite RendererColor num tom amarelado, para o jogador ler "rápido e frágil" de longe.
Enemy_Tank
EnemyStats:maxHealth120,moveSpeed1.2,contactDamage25.TransformScale 1.5.Rigidbody2DMass 5, para ele empurrar e não ser empurrado.
Agora o teste que prova o valor da variante: abra Enemy_Base e aumente o CapsuleCollider2D. Volte para a cena com os três tipos e veja: os três ganharam o collider novo, porque nenhum sobrescreveu esse componente. Depois mude moveSpeed da base para 3. Só a base muda; Fast e Tank mantêm os valores próprios, porque os dois têm override nesse campo.
Por fim, o chefe. Clique com o botão direito em Enemy_Tank.prefab e escolha Create > Prefab Variant, criando Enemy_Boss. No Prefab Mode dele, mude a escala para 2.5, a vida para 600 e adicione um componente que só o chefe tem. Arquivo BossPhase.cs:
using UnityEngine;
public class BossPhase : MonoBehaviour
{
[SerializeField] private SpriteRenderer spriteRenderer;
[SerializeField] private Color enragedColor = Color.red;
[SerializeField, Range(0f, 1f)] private float enrageThreshold = 0.3f;
private bool enraged;
public void OnHealthChanged(int current, int max)
{
if (enraged || max <= 0)
{
return;
}
float ratio = (float)current / max;
if (ratio <= enrageThreshold)
{
enraged = true;
spriteRenderer.color = enragedColor;
}
}
}
O componente aparece com o ícone de mais no Inspector da variante: é um componente adicionado, que não existe no Tank nem na base. O chefe herda do Tank a massa e o tipo de corpo, e do base o collider e o script de movimento. Para ligar o OnHealthChanged, exponha um evento no EnemyStats (por exemplo um UnityEvent<int, int>) e conecte pelo Inspector do chefe.
Montar a família de inimigos é a parte gostosa. O que costuma travar é o resto: fazer esses inimigos nascerem nas ondas certas, conversarem com HUD, som e pontuação, e o projeto continuar fácil de mexer quando o jogo cresce. É nesse ponto de juntar tudo num jogo que fecha que ter um caminho guiado faz diferença.
Nested prefabs e variants juntos
Variante e prefab aninhado se combinam. Suponha que todo inimigo tem um filho HealthBar, que é ele mesmo um prefab (HealthBar.prefab) com Canvas, imagem de fundo e imagem de preenchimento. Esse filho entra no Enemy_Base como prefab aninhado.
O resultado são três camadas de herança trabalhando juntas:
- Trocar a cor do preenchimento em
HealthBar.prefabatualiza a barra de todos os inimigos e de qualquer outro objeto que use a barra. - Mover a barra para cima em
Enemy_Baseatualiza Fast, Tank e Boss. - Subir mais a barra só no
Enemy_Boss(porque ele é maior) vira override do Boss, sem afetar ninguém.
A pergunta para fazer antes de cada edição é "em qual nível essa mudança deveria valer?". Se vale para toda barra, edite o prefab da barra. Se vale para todo inimigo, edite a base. Se vale para um tipo, edite a variante. Essa disciplina é a mesma do princípio de composição que aparece em padrões de projeto para jogos.
Prefab Variant vs ScriptableObject para variar inimigos
As duas ferramentas resolvem "inimigos parecidos com números diferentes", e escolher errado gera retrabalho. O critério que uso:
Use Prefab Variant quando a variação é de estrutura ou visual. O chefe tem um componente a mais, o tanque tem outro collider, o voador não tem Rigidbody com gravidade. Isso é forma do objeto, e variant herda forma muito bem.
Use ScriptableObject quando a variação é só de dados. Se Fast, Tank e Boss diferem apenas em vida, velocidade e dano, um único prefab com um campo EnemyData e três assets de dados é mais simples: o game designer ajusta números numa ficha, compara as três lado a lado e não precisa abrir Prefab Mode. Esse formato também facilita o balanceamento por fórmula ou planilha, porque os números ficam em arquivos pequenos e previsíveis.
Use os dois quando o jogo cresce. Uma combinação comum: uma variante por "arquétipo" de estrutura (terrestre, voador, chefe) e um ScriptableObject por tipo de inimigo com os números. Assim você tem poucas variantes e muitos dados, em vez de quinze variantes onde cada uma sobrescreve três números.
Erros comuns: override preso e cadeia de variantes longa demais
Override preso. Você mexeu na velocidade da variante só para testar e esqueceu. Meses depois, ajusta a velocidade na base e aquela variante não acompanha. Antes de entregar uma variante, abra o dropdown Overrides e confirme que cada item da lista é intencional. O que for resto de teste, reverta.
Aplicar na base sem querer. No Prefab Mode da variante, o botão de aplicar ao pai leva o override para a base e muda todas as irmãs. Se o objetivo era mudar só o chefe, não aplique: deixe como override.
Cadeia longa demais. Base, depois Terrestre, depois Melee, depois Orc, depois Orc Elite, depois Orc Elite de Gelo. Seis níveis e ninguém sabe de onde vem a velocidade do último. Na prática, dois ou três níveis bastam. Se a cadeia passa disso, normalmente a diferença entre os elos é só número, e ela deveria virar dados.
Excluir a base. Variante sem base vira Missing Prefab. Mova e renomeie prefabs só pela janela Project, para o .meta acompanhar.
Próximo passo
Monte a família de quatro inimigos deste post num projeto de teste e faça a prova do collider: uma mudança na base chegando em todos, e uma mudança com override ficando só na variante. Depois experimente a versão híbrida, com um ScriptableObject de dados por tipo, e compare qual das duas você acha mais fácil de balancear. Se a parte de overrides em instância ainda está confusa, volte ao guia de prefab na Unity antes de seguir.
Perguntas frequentes
Qual a diferença entre prefab e Prefab Variant?
Um prefab comum é um molde independente. Uma Prefab Variant é um prefab que herda de outro (a base) e guarda só as diferenças, chamadas overrides. Mudanças na base chegam à variante em todos os campos que ela não sobrescreveu.
Posso criar uma variante de uma variante?
Pode. A Unity permite basear uma variante em qualquer prefab, inclusive em outra variante, formando uma cadeia. Funciona bem com dois ou três níveis; cadeias mais longas ficam difíceis de rastrear, porque um valor pode estar vindo de qualquer elo.
Como saber se um prefab é variante?
Na janela Project e na Hierarchy, a variante tem um ícone de cubo azul com um dos lados hachurado, diferente do cubo liso do prefab comum. No Inspector do asset, o bloco Prefab também mostra qual é a base.
Prefab Variant substitui ScriptableObject?
Não, eles resolvem coisas diferentes. Variant é boa quando o objeto muda de estrutura (componentes, filhos, visual). ScriptableObject é melhor quando só os números mudam e você quer editar dados sem abrir prefab. Muitos projetos usam os dois juntos.


