GameObject e Componentes na Unity: Como a Engine Pensa
Um GameObject na Unity é um recipiente vazio: tem nome, tag, layer e um Transform, e mais nada. Tudo que ele faz, aparecer na tela, colidir, cair, tocar som, levar dano, vem dos componentes que você encaixa nele. Entender essa ideia de composição é o que separa quem "mexe na Unity" de quem constrói jogos que crescem sem virar bagunça.
Para mostrar isso na prática, vamos montar um inimigo 2D completo começando de um objeto vazio, só somando componentes: visual, física, colisão, patrulha, vida e dano. No fim, você vai ver por que três scripts pequenos funcionam melhor que um Inimigo.cs de 400 linhas, e vai reaproveitar dois deles num objeto que nada tem a ver com inimigo.
O que é GameObject na Unity
Tudo que aparece na Hierarchy é um GameObject: o jogador, a câmera, a luz, o chão, cada moeda, cada botão do menu. A classe GameObject em C# representa esse objeto, e dá para criar, achar, ativar e destruir GameObjects por código.
O que um GameObject tem sozinho:
- Nome: só para você se organizar.
- Ativo/inativo: a caixinha no topo do Inspector. Objeto inativo não roda scripts, não renderiza e não colide.
- Tag: um rótulo para identificar o tipo do objeto em código (
Player,Inimigo). - Layer: camada usada por física, câmera e luz para decidir quem interage com quem.
- Transform: posição, rotação e escala. Todo GameObject tem um, obrigatoriamente.
Faça o teste: GameObject > Create Empty. O objeto aparece na Hierarchy, mas não aparece na Scene. Ele existe, tem posição, mas não tem nada para desenhar.
Componentes: o que dá comportamento
Componente é uma peça de comportamento ou de dados que vive dentro de um GameObject. A Unity vem com centenas prontos:
- Sprite Renderer / Mesh Renderer: desenham algo.
- Rigidbody 2D / Rigidbody: fazem o objeto obedecer à física.
- Box Collider 2D, Capsule Collider: dão forma para colisão.
- Audio Source: toca som.
- Camera, Light: transformam o objeto em câmera ou luz.
- Animator: toca animações.
E todo script seu que herda de MonoBehaviour também é um componente. É por isso que você arrasta um script para um objeto: está encaixando uma peça nova nele.
Uma "Main Camera" não é um tipo especial de objeto. É um GameObject comum com os componentes Camera e Audio Listener (e, na URP, um componente extra com as configurações de câmera do pipeline). Uma "Directional Light" é um GameObject com o componente Light. A Unity só já monta essas combinações para você no menu.
Transform: o componente que todo objeto tem
O Transform guarda três coisas: Position, Rotation e Scale. Ele não pode ser removido, e é o único componente garantido em qualquer GameObject.
Dois detalhes que confundem no começo:
- Os valores do Inspector são locais. Se o objeto tem um pai, a posição mostrada é relativa ao pai, não ao mundo. Em código,
transform.positioné a posição no mundo etransform.localPositioné a relativa ao pai. - Na UI, o Transform vira RectTransform. Objetos dentro de um Canvas usam o RectTransform, que acrescenta âncoras, pivô, largura e altura. É ele que faz um botão ficar no canto da tela em qualquer resolução.
Por código, o Transform está sempre acessível pela propriedade transform de qualquer script, sem precisar buscar.
Montando um inimigo só com componentes
Projeto Universal 2D. Vamos montar um slime que patrulha entre dois pontos, causa dano ao encostar e morre com três golpes.
Estrutura na Hierarchy
- Create Empty, nome
SlimeGrupo. É só um organizador. - Dentro dele, Create Empty com o nome
Slime. Esse é o inimigo. - Ainda dentro de
SlimeGrupo(irmãos do Slime, não filhos), dois objetos vazios:PontoAem(-3, 0, 0)ePontoBem(3, 0, 0).
Por que os pontos são irmãos e não filhos do Slime? Porque filho se move junto com o pai. Se os pontos fossem filhos, eles andariam com o slime e ele nunca chegaria a nenhum. Essa é a regra de hierarquia na prática, e vamos voltar a ela.
Componentes prontos
No Slime:
- Sprite Renderer: em Sprite, escolha um sprite qualquer (ou crie com Create > 2D > Sprites > Circle). O objeto aparece.
- Rigidbody 2D: Body Type em Kinematic. O slime vai se mover por código, sem gravidade e sem ser empurrado.
- Capsule Collider 2D: ajuste ao tamanho do sprite.
Três componentes, zero código, e você já tem um objeto visível e com corpo físico.
Script 1: Patrulha
Arquivo Patrulha.cs:
using UnityEngine;
[RequireComponent(typeof(Rigidbody2D))]
public class Patrulha : MonoBehaviour
{
[SerializeField] private Transform pontoA;
[SerializeField] private Transform pontoB;
[SerializeField] private float velocidade = 2f;
private Rigidbody2D rb;
private Transform alvo;
private void Awake()
{
rb = GetComponent<Rigidbody2D>();
alvo = pontoB;
}
private void FixedUpdate()
{
Vector2 novaPosicao = Vector2.MoveTowards(rb.position, alvo.position, velocidade * Time.fixedDeltaTime);
rb.MovePosition(novaPosicao);
if (Vector2.Distance(novaPosicao, alvo.position) < 0.05f)
{
alvo = alvo == pontoA ? pontoB : pontoA;
}
}
}
O [RequireComponent(typeof(Rigidbody2D))] diz à Unity que este script não funciona sem um Rigidbody 2D. Se você adicionar Patrulha a um objeto que não tem, a Unity adiciona o Rigidbody 2D sozinha, e não deixa removê-lo enquanto Patrulha estiver lá. É documentação que o editor faz cumprir.
O GetComponent<Rigidbody2D>() busca outro componente no mesmo GameObject. Fazemos isso uma vez no Awake e guardamos, em vez de buscar a cada frame. O post sobre GetComponent na Unity detalha quando buscar, quando arrastar pelo Inspector e os erros mais comuns.
Script 2: Vida
Arquivo Vida.cs:
using UnityEngine;
using UnityEngine.Events;
[DisallowMultipleComponent]
public class Vida : MonoBehaviour
{
[SerializeField] private int vidaMaxima = 3;
[SerializeField] private UnityEvent aoMorrer;
private int vidaAtual;
public int VidaAtual => vidaAtual;
private void Awake()
{
vidaAtual = vidaMaxima;
}
public void ReceberDano(int quantidade)
{
if (vidaAtual <= 0)
{
return;
}
vidaAtual = Mathf.Max(vidaAtual - quantidade, 0);
if (vidaAtual == 0)
{
aoMorrer.Invoke();
Destroy(gameObject);
}
}
}
[DisallowMultipleComponent] impede duas Vida no mesmo objeto, o que só geraria bug. O UnityEvent aoMorrer aparece no Inspector como uma lista onde você liga, sem código, o que acontece na morte: tocar um som, soltar uma moeda, somar pontos.
Script 3: Dano ao tocar
Arquivo DanoAoTocar.cs:
using UnityEngine;
public class DanoAoTocar : MonoBehaviour
{
[SerializeField] private int dano = 1;
private void OnCollisionEnter2D(Collision2D colisao)
{
if (colisao.gameObject.TryGetComponent(out Vida vida))
{
vida.ReceberDano(dano);
}
}
}
Este script não sabe nada de slime, nem de jogador. Ele só diz: "quem encostar em mim e tiver Vida, leva dano". O TryGetComponent tenta pegar o componente Vida do outro objeto e devolve false se não tiver, sem erro.
Adicione os três scripts ao Slime, arraste PontoA e PontoB nos campos da Patrulha e aperte Play. O slime vai e volta. Dê ao jogador um Rigidbody 2D Dynamic, um collider e uma Vida, e ele passa a levar dano ao encostar.
Hierarquia pai e filho
Quando um GameObject é filho de outro na Hierarchy:
- Ele se move, gira e escala junto com o pai.
- Os valores do Transform dele no Inspector são relativos ao pai.
- Desativar o pai desativa todos os filhos.
Isso é ótimo para montar objetos compostos: o slime pode ter um filho Visual com o Sprite Renderer (para você animar ou inverter o desenho sem mexer na física) e um filho Sombra. E é péssimo quando o objeto deveria ficar parado no mundo, como os pontos de patrulha. A pergunta para decidir é sempre: "isto deve se mover junto com aquilo?".
Montar um inimigo assim é tranquilo. A dificuldade aparece quando o jogo tem dez tipos de inimigo, jogador, itens, armadilhas, UI e save, e cada sistema precisa conversar com os outros sem que mudar um quebre três. Desenhar essa arquitetura de componentes com consciência, e não por tentativa e erro, é o que mais acelera quem quer terminar um jogo de verdade.
Composição vs herança: como a Unity pensa
A tentação de quem vem de programação tradicional é criar uma classe Inimigo com tudo dentro: movimento, vida, dano, animação, som, IA. Depois Slime : Inimigo, Morcego : Inimigo, e uma árvore de herança que cresce.
O problema aparece rápido:
- Uma caixa destrutível precisa de vida, mas não é inimigo. Herda de
Inimigo? Copia o código de vida? - Um espinho causa dano ao tocar, mas não se move nem tem vida.
- O jogador também tem vida. Herda de onde?
Com composição, a resposta é trivial. Veja o que os mesmos scripts montam:
| Objeto | Patrulha | Vida | DanoAoTocar |
|---|---|---|---|
| Slime | sim | sim | sim |
| Espinho | não | não | sim |
| Caixa destrutível | não | sim | não |
| Plataforma móvel | sim | não | não |
| Jogador | não | sim | não |
Cinco objetos diferentes, três scripts, zero código duplicado. É assim que a Unity foi desenhada para funcionar: o GameObject é o "quem", os componentes são o "o que faz".
Herança continua útil em pontos específicos (uma classe base de arma, por exemplo), mas a estrutura principal do jogo é composição. Se quiser se aprofundar em como organizar isso em projetos maiores, o post sobre padrões de projeto em jogos mostra os padrões que aparecem mais em game dev.
Erros comuns com GameObject e componentes
"Can't add script": nome do arquivo diferente do nome da classe, ou erro de compilação no Console.
NullReferenceException ao usar GetComponent: o componente procurado não está no mesmo GameObject. Se estiver num filho, use GetComponentInChildren<T>().
Objeto filho "fugindo": ele herda o movimento do pai. Tire da hierarquia ou crie um pai organizador parado.
Escala estranha num filho: o pai tem escala diferente de 1. Mantenha a escala dos pais em (1, 1, 1) e escale só o objeto final ou o filho visual.
Script que faz tudo: se você descreve o script usando "e" mais de duas vezes ("ele anda e pula e atira e toca som"), divida.
GetComponent em todo Update: busque uma vez no Awake e guarde numa variável.
Próximo passo
Pegue o jogo mais simples que você já fez e reescreva um objeto dele por composição: separe movimento, vida e dano em scripts próprios. Depois crie um objeto novo só combinando scripts que já existem, sem escrever nenhuma linha. Quando isso funcionar, você entendeu a Unity.
Se a linguagem dos scripts ainda é um ponto fraco, comece pelo post sobre qual linguagem a Unity usa e o que estudar de C# primeiro.
Perguntas frequentes
O que é um GameObject na Unity?
É o objeto base de tudo que existe numa cena: personagem, câmera, luz, parede, botão de menu. Sozinho, ele não faz nada além de ter nome, tag, layer e um Transform. O comportamento vem dos componentes que você adiciona a ele.
Qual a diferença entre Transform e RectTransform?
O Transform guarda posição, rotação e escala de objetos comuns no mundo 2D ou 3D. O RectTransform é a versão usada em interface (objetos dentro de um Canvas) e acrescenta âncoras, pivô, largura e altura, para a UI se adaptar a resoluções diferentes.
Posso ter dois scripts iguais no mesmo GameObject?
Pode, a Unity permite vários componentes do mesmo tipo por padrão. Quando isso não faz sentido (dois componentes de vida no mesmo inimigo, por exemplo), coloque o atributo DisallowMultipleComponent na classe e o editor passa a bloquear a duplicata.
Para que serve o RequireComponent?
É um atributo que você coloca na classe do script dizendo que ele depende de outro componente, como um Rigidbody2D. Ao adicionar o script, a Unity adiciona o componente exigido junto e impede que ele seja removido enquanto o script estiver no objeto.



