GetComponent na Unity: Como Acessar Outros Componentes
Unity GetComponent é o método que um script usa para pegar outro componente do mesmo GameObject: o Rigidbody2D para mover, o SpriteRenderer para piscar, o Animator para trocar animação. A forma básica é GetComponent<Rigidbody2D>(), e o jeito certo de usar é chamar uma vez no Awake, guardar numa variável e nunca mais procurar.
Aqui você vai ver onde chamar cada variação sem pesar o jogo: cache no Awake, TryGetComponent na colisão, GetComponentInChildren e GetComponentInParent com uma hitbox de verdade, e quando é melhor arrastar a referência no Inspector. Todo o código é para a Unity 6.3 LTS.
O que GetComponent faz
Na Unity, um GameObject é uma caixa vazia com um Transform. O comportamento vem dos componentes que você adiciona: SpriteRenderer, Collider2D, Rigidbody2D, Animator e os seus scripts. Cada componente é um objeto separado, e um script não enxerga os vizinhos automaticamente.
GetComponent<T>() percorre os componentes do GameObject em que o script está e devolve o primeiro do tipo T. Se não achar, devolve null. O T pode ser um tipo da Unity, um script seu ou uma interface que algum componente implemente.
Isso explica dois comportamentos que pegam iniciante. Primeiro, ele só procura no mesmo GameObject: um SpriteRenderer que está num filho não é encontrado. Segundo, se o objeto tem dois componentes do mesmo tipo (dois BoxCollider2D, por exemplo), você recebe um deles, e a ordem não é algo em que você deve confiar.
Unity getcomponent: sintaxe e cache no Awake
O padrão que vai em quase todo script. Arquivo PlayerMovement.cs:
using UnityEngine;
using UnityEngine.InputSystem;
[RequireComponent(typeof(Rigidbody2D))]
public class PlayerMovement : MonoBehaviour
{
[SerializeField] private float moveSpeed = 6f;
private Rigidbody2D body;
private SpriteRenderer spriteRenderer;
private InputAction moveAction;
private float horizontalInput;
private void Awake()
{
body = GetComponent<Rigidbody2D>();
spriteRenderer = GetComponent<SpriteRenderer>();
moveAction = InputSystem.actions.FindAction("Move");
}
private void Update()
{
horizontalInput = moveAction.ReadValue<Vector2>().x;
if (horizontalInput != 0f)
{
spriteRenderer.flipX = horizontalInput < 0f;
}
}
private void FixedUpdate()
{
body.linearVelocity = new Vector2(horizontalInput * moveSpeed, body.linearVelocity.y);
}
}
Três decisões neste script:
- Cache no Awake. O
GetComponentroda uma vez por instância. OUpdatee oFixedUpdateusam as variáveisbodyespriteRenderer, que são só uma leitura de campo. O Awake é o lugar certo porque ele serve para o objeto preparar a si mesmo, e o componente está no mesmo objeto. [RequireComponent(typeof(Rigidbody2D))]. Ao adicionar o script, a Unity adiciona oRigidbody2Djunto se ele não existir e impede que alguém remova o Rigidbody2D enquanto o script estiver lá. É uma garantia em tempo de editor de que oGetComponentnunca vai voltarnull.- Campo
private. Ninguém de fora precisa trocar o Rigidbody do jogador. Se outro script precisar, exponha um método.
Por que não chamar no Update? Uma chamada é rápida, mas ela procura na lista de componentes toda vez. Com 200 inimigos fazendo três GetComponent por frame a 60 FPS, são 36 mil buscas por segundo para pegar sempre as mesmas referências. O cache troca isso por zero. Se você quer entender onde a performance realmente vai embora num jogo, o post otimização de performance para 60 FPS mostra como medir antes de otimizar.
TryGetComponent em colisão e trigger
Na colisão, você não sabe de antemão o que bateu em você. Pode ser o jogador, uma parede, uma moeda. O TryGetComponent faz a pergunta e entrega a resposta numa linha. Arquivo DamageZone.cs:
using UnityEngine;
public class DamageZone : MonoBehaviour
{
[SerializeField] private int damage = 1;
private void OnTriggerEnter2D(Collider2D other)
{
if (other.TryGetComponent(out Health health))
{
health.TakeDamage(damage);
}
}
}
E o Health.cs que ele procura:
using UnityEngine;
public class Health : MonoBehaviour
{
[SerializeField] private int maxHealth = 3;
private int currentHealth;
private void Awake()
{
currentHealth = maxHealth;
}
public void TakeDamage(int amount)
{
currentHealth -= amount;
Debug.Log(name + " ficou com " + currentHealth + " de vida.");
if (currentHealth <= 0)
{
Destroy(gameObject);
}
}
}
Compare com a versão sem Try: Health health = other.GetComponent<Health>(); if (health != null) { ... }. Faz a mesma coisa em duas linhas. A documentação de Component.TryGetComponent acrescenta um detalhe técnico: quando o componente não existe, ele não aloca memória no Editor, diferente do GetComponent. Isso só importa no Editor, mas é justamente onde você testa, e trigger acontece toda hora.
Repare que aqui não tem como fazer cache: cada colisão traz um objeto diferente. Esse é o uso legítimo de buscar componente durante o jogo, porque acontece num evento, não a cada frame.
Uma variação útil é procurar por interface. Se baús, inimigos e caixas quebráveis implementam uma interface IDamageable, o DamageZone faz TryGetComponent(out IDamageable target) e funciona com todos, sem saber qual é qual. Esse é o padrão Component aplicado, explicado em padrões de projeto em jogos.
A interface fica num arquivo próprio, IDamageable.cs:
public interface IDamageable
{
void TakeDamage(int amount);
}
O Health passa a declarar public class Health : MonoBehaviour, IDamageable, e um script Breakable de caixa faz o mesmo com a própria regra (vira pedaços no primeiro golpe, por exemplo). Na zona de dano, a linha muda só no tipo: if (other.TryGetComponent(out IDamageable target)) { target.TakeDamage(damage); }. O ganho aparece quando o projeto cresce: um espinho, uma bala e uma explosão causam dano em qualquer coisa que saiba receber dano, e você não precisa editar o espinho cada vez que inventa um objeto novo. Um cuidado: a interface não é um componente da Unity, então ela não aparece no Inspector nem funciona com RequireComponent. Ela só existe para o código perguntar "você sabe tomar dano?".
Até aqui são peças pequenas. A dificuldade real começa quando inimigo, arma, animação e vida precisam funcionar juntos num jogo inteiro, com prefab reaproveitado, hierarquia de vários níveis e bug que só aparece na fase três. É nesse ponto que estudar sozinho costuma travar.
GetComponentInChildren e GetComponentInParent
Personagem de jogo raramente é um GameObject só. O padrão comum é um objeto raiz com o script e o Rigidbody, um filho "Visual" com o SpriteRenderer e o Animator, e um filho "Hurtbox" com o collider que recebe golpe. Isso permite girar o visual sem girar a física e ter hitboxes de tamanhos diferentes.
Inimigo (Rigidbody2D, Health, EnemyAI)
├── Visual (SpriteRenderer, Animator)
└── Hurtbox (BoxCollider2D, Is Trigger)
Dois problemas aparecem com essa estrutura. O script na raiz precisa do Animator, que está num filho. E quando a espada do jogador acerta a Hurtbox, o other do trigger é o collider da Hurtbox, que não tem Health.
Para o primeiro, GetComponentInChildren. Arquivo EnemyAI.cs:
using UnityEngine;
public class EnemyAI : MonoBehaviour
{
private Animator animator;
private static readonly int IsWalking = Animator.StringToHash("IsWalking");
private void Awake()
{
animator = GetComponentInChildren<Animator>();
}
public void SetWalking(bool walking)
{
animator.SetBool(IsWalking, walking);
}
}
Para o segundo, GetComponentInParent na arma. Arquivo SwordHitbox.cs:
using UnityEngine;
public class SwordHitbox : MonoBehaviour
{
[SerializeField] private int damage = 2;
private void OnTriggerEnter2D(Collider2D other)
{
Health health = other.GetComponentInParent<Health>();
if (health != null)
{
health.TakeDamage(damage);
}
}
}
O que a documentação garante sobre esses dois: GetComponentInChildren sempre procura primeiro no próprio GameObject e depois desce pelos filhos, em profundidade. O parâmetro includeInactive vale false por padrão, então filhos desativados são ignorados; passe true se o componente pode estar num objeto escondido. GetComponentInParent faz o caminho inverso: começa no próprio objeto e sobe pelos pais. Ou seja, o SwordHitbox também funciona se o Health estiver no mesmo objeto do collider.
Existem também as versões no plural (GetComponents, GetComponentsInChildren), que devolvem todos. Servem, por exemplo, para trocar a cor de todos os SpriteRenderer de um personagem montado em partes.
Referência pelo Inspector vs GetComponent
Existe um terceiro caminho, e muitas vezes é o melhor: arrastar a referência no Inspector.
using UnityEngine;
public class EnemyVisual : MonoBehaviour
{
[SerializeField] private SpriteRenderer spriteRenderer;
[SerializeField] private Animator animator;
public void Flash(Color color)
{
spriteRenderer.color = color;
}
}
Com [SerializeField] private, o campo aparece no Inspector e você arrasta o filho "Visual" para ele. Sem busca nenhuma em tempo de jogo.
Quando usar cada um:
- GetComponent no Awake: componente no mesmo objeto, sempre presente. Combine com
RequireComponent. - Inspector: componente em outro objeto (filho específico, objeto da cena, outro prefab), ou quando há mais de um do mesmo tipo e você precisa de um específico. Deixa a ligação visível para quem abre o prefab.
- TryGetComponent / InParent em evento: o outro objeto só é conhecido na hora da colisão, do raycast ou do clique.
- GetComponentInChildren no Awake: quando a hierarquia do prefab pode mudar e você quer que o script ache sozinho. É mais frágil que o Inspector se houver dois componentes do mesmo tipo nos filhos.
Uma prática que junta os dois: arrastar no Inspector e usar o método Reset() para preencher automaticamente. A Unity chama Reset quando você adiciona o componente ou clica em Reset no menu dele, então private void Reset() { spriteRenderer = GetComponentInChildren<SpriteRenderer>(); } preenche o campo no editor e você só confere.
Erros comuns: null, componente errado, chamar no Update
NullReferenceException na linha que usa o componente. O GetComponent não achou nada. Causas, em ordem de frequência: o componente está num filho (use InChildren ou o Inspector), o script está no objeto errado, ou o tipo é diferente (Rigidbody em vez de Rigidbody2D, Collider em vez de Collider2D). O post NullReferenceException na Unity tem o roteiro completo de investigação.
Física 3D e 2D misturadas. GetComponent<Rigidbody>() num objeto 2D volta null, sempre. Os tipos 2D terminam em "2D" e não se misturam com os 3D.
GetComponent no Update. Funciona, mas é busca repetida à toa. Cache no Awake.
GetComponent de outro objeto no Awake. Pegar componente do próprio objeto no Awake é seguro. Ler dados de outro objeto no Awake não é, porque ele pode não ter inicializado ainda. Pegue a referência e leia os valores no Start.
Esperar que GetComponent procure na cena. Ele procura num GameObject. Para achar algo na cena, existem FindFirstObjectByType<T>() e FindAnyObjectByType<T>(), que substituem o antigo FindObjectOfType. Use no Start, uma vez, e só quando arrastar no Inspector não for possível.
Próximo passo
Monte o inimigo com a hierarquia raiz, Visual e Hurtbox, e faça a espada do jogador causar dano via GetComponentInParent. Depois troque o GetComponentInChildren do EnemyAI por um campo arrastado no Inspector e compare qual dos dois você prefere manter num prefab que vai ser duplicado vinte vezes. Quando um null aparecer no caminho, o post sobre NullReferenceException é a parada seguinte.
Perguntas frequentes
GetComponent é pesado na Unity?
Uma chamada isolada é barata. O problema é chamar dentro do Update para pegar o mesmo componente todo frame, em muitos objetos. Guarde o resultado numa variável no Awake e use a variável no resto do script.
Qual a diferença entre GetComponent e TryGetComponent?
GetComponent devolve o componente ou null. TryGetComponent devolve true ou false e entrega o componente num parâmetro out, o que deixa o código de colisão mais limpo. A documentação também registra que TryGetComponent não aloca memória no Editor quando o componente não existe.
GetComponentInChildren procura no próprio objeto?
Sim. Ele sempre procura primeiro no GameObject em que foi chamado e depois desce pelos filhos em profundidade. Por padrão ignora filhos inativos; passe true no parâmetro includeInactive para incluir.
Como pegar o Rigidbody2D com GetComponent?
Declare um campo private Rigidbody2D body e, no Awake, faça body = GetComponent<Rigidbody2D>(). Acrescente [RequireComponent(typeof(Rigidbody2D))] na classe para a Unity garantir que o componente exista no objeto.



