Unity Behavior: Árvore de Comportamento Visual para IA

Behavior tree na Unity com o pacote Unity Behavior: Blackboard, Behavior Graph, patrulha e perseguição visual e um nó de ação próprio em C#, no Unity 6.3.
Unity Behavior: Árvore de Comportamento Visual para IA
Uma behavior tree na Unity (a unity behavior tree que aparece em todo tutorial de IA de inimigo) é uma árvore de decisões que o agente percorre várias vezes por segundo: "consigo ver o jogador? Então persigo. Não consigo? Então patrulho". O pacote oficial Unity Behavior (com.unity.behavior) deixa você montar essa árvore num editor visual de grafo, com Blackboard para os dados e nós prontos de navegação, e criar seus próprios nós em C# quando os prontos não bastam.
Aqui você monta um inimigo 3D que patrulha entre pontos e persegue o jogador quando o vê, cria um nó de ação próprio em C#, depura a árvore em Play Mode e, no fim, entende quando não usar nada disso.
Behavior tree vs máquina de estados
Uma máquina de estados (FSM) responde "em que estado estou e para onde posso ir". Patrulha vai para Perseguição quando vê o jogador, Perseguição volta para Patrulha quando perde. Com 3 estados, você tem poucas transições. Com 8 estados, cada um podendo ir para vários outros, as transições explodem e mudar uma regra quebra outras.
Uma behavior tree responde "o que é mais importante fazer agora". A árvore é avaliada de cima para baixo, por prioridade: fugir vem antes de atacar, que vem antes de perseguir, que vem antes de patrulhar. Adicionar um comportamento novo é encaixar um galho na posição de prioridade certa, sem mexer nos outros.
Os dois blocos que você precisa entender:
- Sequence (sequência): executa os filhos em ordem e falha assim que um falha. É o "E": vire para o alvo E ande até ele.
- Try In Order (seletor): tenta os filhos em ordem e para no primeiro que der certo. É o "OU": persiga OU patrulhe. No Unity Behavior o seletor clássico tem esse nome.
Cada nó devolve um status: Running (ainda executando), Success ou Failure. Toda a árvore é feita desses três resultados subindo pelos galhos.
Instalar o Unity Behavior
- Abra Window > Package Management > Package Manager.
- No painel da esquerda, escolha Unity Registry.
- Busque por Behavior e clique em Install.
Conferido em outubro de 2026: o manual do Unity 6.3 lista o pacote com.unity.behavior na versão 1.0.16, com estado released para o editor 6000.3. Se você está em outra versão do editor, o Package Manager mostra a versão compatível.
Para os nós de navegação usarem NavMesh, instale também o pacote AI Navigation, adicione um NavMesh Surface ao chão da cena e clique em Bake. No inimigo, coloque um NavMeshAgent. É ele que faz o inimigo contornar paredes em vez de andar em linha reta contra elas.
Behavior Graph: Blackboard, Agent e nós
São três conceitos.
Behavior Graph é o asset que guarda a árvore. Crie com botão direito no Project, Create > Behavior > Behavior Graph. Dê o nome EnemyAI e dê dois cliques para abrir o editor.
Blackboard é a memória do grafo: variáveis com nome e tipo que os nós leem e escrevem. Ela fica no painel lateral do editor. Crie estas variáveis clicando no +:
Targetdo tipo GameObject: o jogador.Waypointsdo tipo List de GameObject: os pontos de patrulha.CanSeeTargetdo tipo Boolean: se o inimigo está vendo o jogador agora.
O Blackboard já vem com uma variável Self, que representa o próprio GameObject que roda o grafo.
Behavior Agent é o componente que roda o grafo num GameObject. No inimigo, clique em Add Component, busque Behavior Agent e arraste o asset EnemyAI para o campo Graph. No Inspector do agente aparecem as variáveis do Blackboard, e é lá que você arrasta os waypoints da cena e o jogador.
Montar patrulha e perseguição visual
A árvore que vamos montar, de cima para baixo:
- On Start, com a opção Repeat ligada no Inspector do nó, para a árvore recomeçar sempre que terminar.
- Restart com a condição Variable Value Changed apontando para
CanSeeTarget. Ele reinicia o galho de baixo quando a visão muda, então o inimigo larga a patrulha no meio no instante em que vê o jogador. - Conditional Branch com a condição Variable Comparison:
CanSeeTargetigual atrue. - Na saída True, um Sequence com dois filhos: o nosso nó
Look At Target(criado na próxima seção) e Navigate To Target, comSelfcomo agente eTargetcomo destino. - Na saída False, o nó Patrol, com
Selfcomo agente eWaypointscomo a lista de pontos.
Para adicionar cada nó, clique com o botão direito no fundo do editor e use Add: os nós de navegação ficam em Action > Navigation, e Sequence, Conditional Branch e Restart ficam em Flow. Ligue as portas arrastando da saída de um nó para a entrada do outro.
Falta preencher o CanSeeTarget. Ver o jogador é física e geometria, e isso é mais claro em C# do que em nós. Crie EnemySight.cs no inimigo:
using Unity.Behavior;
using UnityEngine;
[RequireComponent(typeof(BehaviorGraphAgent))]
public class EnemySight : MonoBehaviour
{
[SerializeField] private Transform target;
[SerializeField] private float viewDistance = 12f;
[SerializeField] private float viewAngle = 90f;
[SerializeField] private float eyeHeight = 1.6f;
[SerializeField] private LayerMask obstacleMask;
[SerializeField] private float checkInterval = 0.2f;
private BehaviorGraphAgent agent;
private bool lastCanSee;
private float nextCheckTime;
private void Awake()
{
agent = GetComponent<BehaviorGraphAgent>();
}
private void Start()
{
agent.SetVariableValue("Target", target.gameObject);
agent.SetVariableValue("CanSeeTarget", false);
}
private void Update()
{
if (Time.time < nextCheckTime)
{
return;
}
nextCheckTime = Time.time + checkInterval;
bool canSee = CanSeeTarget();
if (canSee != lastCanSee)
{
lastCanSee = canSee;
agent.SetVariableValue("CanSeeTarget", canSee);
}
}
private bool CanSeeTarget()
{
Vector3 eye = transform.position + Vector3.up * eyeHeight;
Vector3 targetPoint = target.position + Vector3.up * (eyeHeight * 0.5f);
Vector3 toTarget = targetPoint - eye;
float distance = toTarget.magnitude;
if (distance > viewDistance)
{
return false;
}
if (distance < 0.01f)
{
return true;
}
if (Vector3.Angle(transform.forward, toTarget) > viewAngle * 0.5f)
{
return false;
}
return !Physics.Raycast(eye, toTarget / distance, distance, obstacleMask, QueryTriggerInteraction.Ignore);
}
}
SetVariableValue é o método do BehaviorGraphAgent que escreve no Blackboard daquele agente. O script só escreve quando o valor muda, o que importa porque o nó Restart reage a mudança: escrever true a cada frame não reiniciaria nada, mas deixaria o fluxo mais difícil de seguir. A checagem roda a cada 0,2 s, não todo frame: visão de inimigo não precisa de precisão de 60 Hz, e dez inimigos fazendo raycast todo frame é custo à toa.
Repare quanto da IA já depende de coisas fora do grafo: física para a visão, NavMesh para andar, animação para parecer viva, vida e dano para o combate ter consequência. É nessa integração que projeto solo costuma parar, porque cada peça funciona sozinha e o conjunto não. Montar um jogo inteiro, com IA conversando com o resto dos sistemas, é exatamente o que um curso de Unity com projeto completo faz você praticar.
Criar um nó de ação em C#
Os nós prontos cobrem o básico. Quando falta algo, você cria um nó. No editor do grafo, clique com o botão direito e escolha Create new > Action. Dê o nome Look At Target, mantenha a categoria e escreva a frase do nó (a story): [Agent] turns to face [Target]. Cada palavra entre colchetes vira um campo ligado ao Blackboard. Ao clicar em Create, o pacote gera um script. Edite-o para ficar assim, em LookAtTargetAction.cs:
using System;
using Unity.Behavior;
using Unity.Properties;
using UnityEngine;
using Action = Unity.Behavior.Action;
[Serializable, GeneratePropertyBag]
[NodeDescription(name: "Look At Target", story: "[Agent] turns to face [Target]", category: "Action", id: "c41f0a2e9b7d4f3a8e15d6b2a0c9e7f1")]
public partial class LookAtTargetAction : Action
{
[SerializeReference] public BlackboardVariable<GameObject> Agent;
[SerializeReference] public BlackboardVariable<GameObject> Target;
[SerializeReference] public BlackboardVariable<float> TurnSpeed = new BlackboardVariable<float>(360f);
[SerializeReference] public BlackboardVariable<float> Tolerance = new BlackboardVariable<float>(5f);
protected override Status OnStart()
{
if (Agent.Value == null || Target.Value == null)
{
return Status.Failure;
}
return Status.Running;
}
protected override Status OnUpdate()
{
Transform agentTransform = Agent.Value.transform;
Vector3 toTarget = Target.Value.transform.position - agentTransform.position;
toTarget.y = 0f;
if (toTarget.sqrMagnitude < 0.0001f)
{
return Status.Success;
}
Quaternion desired = Quaternion.LookRotation(toTarget);
agentTransform.rotation = Quaternion.RotateTowards(agentTransform.rotation, desired, TurnSpeed.Value * Time.deltaTime);
bool aligned = Quaternion.Angle(agentTransform.rotation, desired) <= Tolerance.Value;
return aligned ? Status.Success : Status.Running;
}
protected override void OnEnd()
{
}
}
O que cada parte faz:
using Action = Unity.Behavior.Action;evita a ambiguidade comSystem.Action. O gerador já coloca essa linha.[GeneratePropertyBag]epartialexistem porque o pacote gera código para ler os campos do nó. Mantenha os dois.[NodeDescription]define nome, frase e categoria no menu. Oidé gerado na criação e identifica o nó: não copie oidde outro nó.- Campos
publiccom[SerializeReference]são a exceção à regra de usar[SerializeField] private: o pacote exige esse formato para ligar o campo ao Blackboard. OnStartroda uma vez quando o nó começa.OnUpdateroda a cada tick enquanto devolverRunning.OnEndroda quando o nó termina ou é interrompido, bom para limpar estado.
O nó devolve Running enquanto gira e Success quando está alinhado, então a Sequence só passa para o Navigate To Target depois que o inimigo encarou o jogador. É um detalhe pequeno que faz a IA parecer que reagiu, em vez de sair andando de lado.
Depurar a árvore em Play Mode
O editor mostra a árvore rodando ao vivo:
- Com o grafo aberto, clique em Debug na barra superior do editor. O menu lista os agentes da cena que usam esse grafo.
- Escolha o inimigo que você quer acompanhar.
- Aperte Play. Os nós ganham ícones de status enquanto executam.
Deixe a janela do grafo e a Game view lado a lado. Ande na frente do inimigo e veja a execução pular do Patrol para a Sequence de perseguição. Se nada muda, o problema está antes do grafo: abra o Inspector do Behavior Agent em Play Mode e veja se CanSeeTarget está mudando. Se não muda, o defeito está no EnemySight (layer de obstáculo cobrindo o próprio jogador é o clássico).
Outros problemas comuns: Patrol parado porque a lista Waypoints está vazia no Inspector do agente, e Navigate To Target sem efeito porque o NavMesh não foi bakeado ou o inimigo nasceu fora dele.
Quando NÃO usar: inimigo simples
Behavior tree é ferramenta para IA com muitas decisões. Para um slime que anda até a borda e vira, ou um morcego que voa em seno e mergulha quando o jogador passa embaixo, ela é peso morto: mais um pacote, mais um editor, mais um lugar para o bug se esconder.
O critério que eu uso:
- Até 3 ou 4 estados com transições óbvias: FSM em C#, com um
enume umswitch. Lê-se em 30 segundos. - Muitas prioridades, galhos reaproveitados entre inimigos, designer ajustando sem programar: Unity Behavior.
- Inimigo só com padrão de movimento: nem FSM. Um script com o padrão basta.
Se a sua IA cabe numa máquina de estados, o post de máquina de estados na Unity mostra o caminho mais curto. E para entender por que State, Observer e companhia aparecem tanto em código de jogo, vale ler padrões de projeto em jogos.
Próximo passo
Com patrulha e perseguição funcionando, o próximo degrau é dar prioridade a mais um comportamento: troque o Conditional Branch por um Try In Order com três galhos (atacar se perto, perseguir se vê, patrulhar), cada um protegido por uma condição. Depois, crie um segundo inimigo reaproveitando o mesmo grafo com outros valores no Blackboard. E se você também usa Godot, compare com a behavior tree no Godot: o conceito é idêntico, e perceber isso é o que faz o conhecimento valer em qualquer engine.
Perguntas frequentes
O que é o pacote Unity Behavior?
É o pacote oficial da Unity (com.unity.behavior) para criar IA com behavior trees num editor visual de grafo. Você monta a lógica com nós prontos (sequência, condição, navegação, espera) e pode criar nós próprios em C#. Ele é instalado pelo Package Manager.
Behavior tree ou máquina de estados: qual usar na Unity?
Máquina de estados é mais simples e basta para inimigos com 2 a 4 estados bem definidos. Behavior tree compensa quando a IA tem muitas decisões com prioridade (fugir se vida baixa, senão atacar se perto, senão perseguir, senão patrulhar) e você quer reaproveitar pedaços entre inimigos.
Como passar informação do C# para o Behavior Graph?
Pelo Blackboard. No componente BehaviorGraphAgent, chame SetVariableValue com o nome da variável e o valor, por exemplo agent.SetVariableValue("CanSeeTarget", true). O grafo lê essa variável nas condições e nos nós.
Unity Behavior funciona em jogo 2D?
A lógica do grafo (sequência, condição, Blackboard, nós próprios) funciona em qualquer jogo. Os nós de navegação prontos foram pensados para movimento em 3D, então em 2D o comum é escrever nós de ação próprios para andar e pular com Rigidbody2D.


