Parâmetros do Animator: SetTrigger, SetBool e SetFloat
O parâmetro Trigger do Animator da Unity serve para eventos pontuais (atacar, pular, levar dano): você chama SetTrigger, a transição consome o sinal e ele volta a falso sozinho. Bool serve para estados que duram, Float para valores contínuos como velocidade, e Int para escolhas discretas como tipo de arma. Escolher o tipo errado é a causa do bug mais comum de animação em Unity: o ataque que toca duas vezes.
Aqui você vai ver os quatro tipos com código C# para Unity 6.3, o uso de Animator.StringToHash e as três formas de resolver o trigger acumulado.
Os quatro parâmetros do Animator e para que serve cada um
Na janela Animator, aba Parameters, o + oferece quatro tipos. A pergunta que decide o tipo é: "quanto tempo essa informação vale?".
| Tipo | Vale por quanto tempo | Exemplos | Método |
|---|---|---|---|
| Bool | Até você mudar | no chão, agachado, morto, bloqueando | SetBool |
| Trigger | Até uma transição consumir | atacar, pular, tomar dano, interagir | SetTrigger / ResetTrigger |
| Float | Contínuo, muda todo frame | velocidade, direção, mira | SetFloat |
| Int | Discreto, muda às vezes | tipo de arma, combo atual, variação de idle | SetInteger |
Os parâmetros são lidos pelas condições das transições. Uma transição de Idle para Attack com a condição Attack (Trigger) só acontece quando o trigger está ligado. Uma transição de Air para Grounded com IsGrounded igual a true acontece enquanto o Bool estiver ligado.
SetBool: estados que duram (andando, no chão)
Bool é para condição que você consegue responder com sim ou não a qualquer momento. "O personagem está no chão agora?" tem resposta em todo frame. Por isso o padrão correto é atualizar o Bool sempre, e não só quando algo muda.
Arquivo PlayerAnimatorBridge.cs, a ponte entre a lógica do personagem e o Animator:
using UnityEngine;
public class PlayerAnimatorBridge : MonoBehaviour
{
[SerializeField] private Animator animator;
[SerializeField] private Rigidbody2D rb;
[SerializeField] private Transform groundCheck;
[SerializeField] private LayerMask groundLayer;
[SerializeField] private float groundRadius = 0.15f;
private static readonly int IsGroundedHash = Animator.StringToHash("IsGrounded");
private static readonly int SpeedHash = Animator.StringToHash("Speed");
private static readonly int VerticalSpeedHash = Animator.StringToHash("VerticalSpeed");
private void Update()
{
bool grounded = Physics2D.OverlapCircle(groundCheck.position, groundRadius, groundLayer);
animator.SetBool(IsGroundedHash, grounded);
animator.SetFloat(SpeedHash, Mathf.Abs(rb.linearVelocity.x));
animator.SetFloat(VerticalSpeedHash, rb.linearVelocity.y);
}
}
O rb.linearVelocity é o nome atual no Unity 6 (o antigo velocity está obsoleto). Com IsGrounded e VerticalSpeed, o Animator consegue escolher sozinho entre subida, queda e aterrissagem sem que o script precise disparar nada.
Um Bool também resolve "ações contínuas", como segurar o escudo: enquanto o botão está pressionado, IsBlocking fica true. Se você usasse Trigger, teria que disparar um para entrar e outro para sair, e qualquer frame perdido deixaria o personagem preso no estado.
SetTrigger: eventos pontuais (atacar, pular)
Trigger é um Bool que se desliga sozinho quando uma transição o consome. É a escolha natural para ações que acontecem num instante.
private static readonly int AttackHash = Animator.StringToHash("Attack");
public void Attack()
{
animator.SetTrigger(AttackHash);
}
O detalhe que muda tudo: se nenhuma transição consome o trigger, ele fica ligado. Ele não expira com o tempo. Se o jogador aperta ataque enquanto o personagem está no meio de outro ataque e não existe transição saindo do estado atual com essa condição, o trigger espera. Quando o ataque termina e o Animator volta para Idle, a transição Idle para Attack encontra o trigger ligado e dispara de novo. Daí o ataque duplo.
Trigger com Any State
O nó Any State é tentador para ações que podem acontecer de qualquer lugar, como tomar dano ou morrer. Uma transição de Any State para Hurt com o trigger Hit funciona, mas tem uma armadilha: por padrão, a transição de Any State tem a opção Can Transition To Self ligada. Se o trigger for disparado de novo enquanto o personagem já está em Hurt, a animação reinicia do começo. Em dano contínuo (veneno, lava), isso deixa o personagem travado no primeiro frame da animação.
Desmarque Can Transition To Self na transição quando a ação não deve reiniciar. E use Any State com moderação: cada transição dele é testada em todo frame, de qualquer estado, e uma condição ampla demais rouba o controle das outras transições. Para morte, prefira um Bool IsDead, porque o personagem morto precisa continuar morto mesmo que outra lógica dispare triggers depois.
SetFloat e SetInteger: velocidade e tipo de arma
Float alimenta Blend Trees e condições do tipo "maior que" ou "menor que". Speed > 0.1 leva de Idle para Run. Para suavizar valores que variam muito, use a sobrecarga com damping: animator.SetFloat(SpeedHash, value, 0.1f, Time.deltaTime). Ela aproxima o parâmetro do alvo ao longo do tempo indicado, desde que você chame todo frame.
Int é para escolhas discretas. Um personagem com espada, arco e cajado pode ter WeaponType com 0, 1 e 2, e transições de Idle para cada conjunto de animações com a condição Equals. Também é útil para contador de combo: ComboStep 1, 2, 3.
private static readonly int WeaponTypeHash = Animator.StringToHash("WeaponType");
public void EquipWeapon(int weaponIndex)
{
animator.SetInteger(WeaponTypeHash, weaponIndex);
}
Prefira Int a vários Bools quando as opções são mutuamente exclusivas. Três Bools (HasSword, HasBow, HasStaff) permitem estados impossíveis, como dois ligados ao mesmo tempo. Um Int não.
Animator.StringToHash para evitar erro de digitação
Todos os métodos aceitam o nome em texto (SetBool("IsGrounded", true)) ou um id inteiro. Passar o texto funciona, mas tem dois problemas: o nome fica espalhado pelo código, e um erro de digitação só aparece em tempo de execução como aviso no Console, com a chamada simplesmente ignorada.
Animator.StringToHash converte o nome em id uma vez. Guardando como static readonly int, o texto existe numa linha só por script. Se o parâmetro mudar de nome no Animator, você troca ali.
Uma dica de organização: concentre todas as chamadas ao Animator num componente só, como o PlayerAnimatorBridge acima. O script de combate chama bridge.Attack(), o de movimento só move. Quando a animação der problema, você sabe onde procurar. Essa separação é a mesma ideia de dividir responsabilidades que aparece em lógica de programação para jogos.
Até aqui cada peça funciona sozinha. O que costuma travar quem estuda por conta própria é juntar input, física, combate e Animator num personagem que responde certo em todas as situações, sem gambiarra em cima de gambiarra. No curso de Unity, isso é construído passo a passo dentro de um jogo completo, então cada parâmetro aparece no contexto em que ele resolve um problema real.
Erros comuns: trigger tocando duas vezes e parâmetro que não muda
O ataque que toca duas vezes
Existem três correções, da mais simples para a mais robusta.
1. ResetTrigger ao entrar no estado. Limpe o trigger assim que o ataque começa, para que cliques extras durante a animação não fiquem guardados. Um StateMachineBehaviour faz isso sem acoplar ao script do personagem. Selecione o estado Attack, clique em Add Behaviour e crie ResetTriggerOnEnter.cs:
using UnityEngine;
public class ResetTriggerOnEnter : StateMachineBehaviour
{
[SerializeField] private string triggerName = "Attack";
public override void OnStateEnter(Animator animator, AnimatorStateInfo stateInfo, int layerIndex)
{
animator.ResetTrigger(triggerName);
}
}
Atenção: limpe só no OnStateEnter. Se você limpar também no OnStateExit, apaga o input de quem queria encadear o próximo golpe de um combo.
2. Bloquear o input durante o ataque. O script de combate ignora o botão enquanto o ataque está ativo, e libera num Animation Event no fim do golpe ou depois de um tempo fixo. É o caminho mais previsível para jogo de ação, e combina com a divisão de startup, active e recovery do sistema de combate corpo a corpo.
3. Trocar Trigger por Bool. IsAttacking fica true enquanto o script considera que há ataque e volta a false quando ele termina. O Animator só reflete o estado do script, e o input acumulado deixa de existir porque o script é a fonte da verdade. Exige uma transição de saída com IsAttacking == false.
Para combos, a solução mais limpa costuma ser a 2 com um buffer curto de input: guarde o clique por uns 0,2 s e só dispare o próximo trigger se ele chegar na janela de encadeamento.
Parâmetro que não muda
- Nome diferente.
isGroundedeIsGroundedsão parâmetros diferentes. Confira o aviso de parâmetro inexistente no Console. - Animator errado. O script referencia o Animator de um prefab no Project, não o da cena. Arraste o componente da hierarquia, não do asset.
- Parâmetro muda, mas a animação não. O problema está na transição: condição errada, Has Exit Time ligado segurando a troca até o fim do clip, ou transição saindo do estado errado. Abra a janela Animator com o jogo rodando e olhe a barra de progresso dos estados e os valores em tempo real na aba Parameters.
- Dois scripts brigando. Um script liga o Bool, outro desliga no mesmo frame. Centralize as chamadas num componente só.
Próximo passo: transições e Has Exit Time
Parâmetro certo com transição mal configurada continua parecendo bug: o pulo responde meio segundo depois, o ataque não cancela. Monte um personagem com IsGrounded, Speed e Attack, deixe a janela Animator aberta ao lado do Game view e observe cada transição acontecer. Depois leia o guia de Has Exit Time e transições, que mostra os valores de Exit Time, Transition Duration e Interruption Source para cada tipo de animação.
Perguntas frequentes
Qual a diferença entre SetTrigger e SetBool no Animator?
O Bool fica ligado até você desligar e serve para estados que duram, como estar no chão. O Trigger liga, é consumido pela primeira transição que o usa e volta a falso sozinho. Use Trigger para eventos pontuais, como atacar ou pular.
Por que minha animação de ataque toca duas vezes na Unity?
Quase sempre é um Trigger que foi disparado enquanto o ataque já estava tocando e ficou guardado até a próxima transição possível. Chame ResetTrigger no momento certo, bloqueie o input durante o ataque ou troque o Trigger por um Bool controlado pelo script.
Como acessar parâmetros do Animator pelo script?
Pegue a referência do componente Animator e use SetBool, SetFloat, SetInteger ou SetTrigger com o nome do parâmetro ou com o id gerado por Animator.StringToHash. O nome precisa ser idêntico ao da aba Parameters, incluindo maiúsculas.
O que acontece se eu digitar o nome do parâmetro errado?
A Unity mostra um aviso no Console dizendo que o parâmetro não existe e a chamada não faz nada. Guardar os nomes em campos static readonly com StringToHash concentra o texto num lugar só e reduz esse erro.



