O que são colisões na Godot (corpo, forma e filtro)
Na Godot 2D, a colisão acontece quando um nó de física (por exemplo, CharacterBody2D, RigidBody2D, StaticBody2D ou Area2D) possui uma ou mais formas de colisão (shapes) e elas se sobrepõem conforme as regras de camadas (layers) e máscaras (masks).
- Body: participa da simulação física (bloqueia, empurra, é bloqueado) ou detecta presença (no caso de
Area2D). - Shape: define o “volume” 2D que colide (retângulo, cápsula, círculo etc.).
- Layers/Masks: definem quem “existe” para quem. Você pode separar jogador, inimigos, cenário e hitboxes sem gambiarras.
Adicionando CollisionShape2D ao Player (alinhamento com Sprite)
Conceito: o Sprite não colide, a Shape colide
Um erro comum é achar que o Sprite2D “tem colisão”. Na prática, o sprite é só visual. Quem colide é o CollisionShape2D (ou CollisionPolygon2D) ligado ao nó de física.
Passo a passo (Player com CharacterBody2D)
- Abra a cena do Player (raiz
CharacterBody2D). - Adicione um filho:
CollisionShape2D. - No Inspector do
CollisionShape2D, em Shape, escolha uma forma adequada (ex.:CapsuleShape2D). - Ajuste o tamanho da shape (arrastando as alças no viewport) para cobrir o corpo do personagem.
- Alinhe a shape ao sprite: selecione o
CollisionShape2De ajuste Position para que a cápsula fique centralizada no personagem (normalmente alinhada ao tronco, não incluindo “vazios” como cabelo/efeitos).
Formas comuns e quando usar
| Shape | Quando usar | Vantagens | Cuidados |
|---|---|---|---|
RectangleShape2D | Caixas, inimigos quadrados, plataformas, objetos simples | Simples, rápido de ajustar | Em personagens, cantos podem “prender” em quinas |
CapsuleShape2D | Personagens que andam e encostam em paredes | Desliza melhor em cantos e rampas | Evite cápsula muito larga (piora a sensação em corredores) |
Dica de alinhamento (para evitar sensação de “flutuar”)
Deixe a shape encostar no “pé” do sprite (base do personagem). Se a cápsula ficar alta demais, o personagem aparenta flutuar; se ficar baixa demais, pode “afundar” visualmente no chão.
Colisão no cenário: StaticBody2D + CollisionShape2D
Conceito: cenário sólido normalmente é StaticBody2D
Para paredes, chão e plataformas sólidas, use StaticBody2D com CollisionShape2D. Ele não se move por física, mas bloqueia outros corpos.
Passo a passo (chão simples)
- Crie uma cena ou nó para o chão:
StaticBody2D. - Adicione um filho
CollisionShape2D. - Escolha
RectangleShape2De dimensione como uma plataforma. - Se houver um visual (ex.:
Sprite2DouTileMap), alinhe a shape para coincidir com a área sólida real (não necessariamente com toda a arte).
Observação sobre TileMap
Se você estiver usando TileMap, as colisões podem ser definidas nos tiles (no editor de tiles). Mesmo assim, o raciocínio de shapes e layers/masks continua o mesmo: o TileMap gera colisores para o cenário.
- Ouça o áudio com a tela desligada
- Ganhe Certificado após a conclusão
- + de 5000 cursos para você explorar!
Baixar o aplicativo
Camadas e máscaras: separando jogador, inimigos, cenário e hitboxes
Conceito: Layer é “onde eu estou”, Mask é “o que eu enxergo”
- Collision Layer: em quais camadas este objeto existe.
- Collision Mask: com quais camadas este objeto interage (colide/detecta).
Exemplo prático: o Player pode estar na camada “Player” e ter máscara “World” e “Enemies”. Assim ele colide com cenário e inimigos, mas ignora hitboxes específicas se você separar em outra camada.
Plano de camadas sugerido (exemplo)
| Camada (Layer) | Número | Uso |
|---|---|---|
| World | 1 | Chão, paredes, obstáculos sólidos |
| Player | 2 | Corpo do jogador |
| Enemy | 3 | Corpo dos inimigos |
| PlayerHitbox | 4 | Área de ataque do jogador (dano) |
| EnemyHurtbox | 5 | Área que recebe dano no inimigo |
Configuração recomendada (exemplo)
- Player (CharacterBody2D): Layer = Player (2). Mask = World (1) + Enemy (3). (Opcional: também colidir com EnemyHurtbox se você quiser empurrar, mas geralmente não.)
- Enemy (CharacterBody2D ou RigidBody2D): Layer = Enemy (3). Mask = World (1) + Player (2).
- World (StaticBody2D/TileMap): Layer = World (1). Mask = Player (2) + Enemy (3).
- PlayerHitbox (Area2D): Layer = PlayerHitbox (4). Mask = EnemyHurtbox (5).
- EnemyHurtbox (Area2D): Layer = EnemyHurtbox (5). Mask = PlayerHitbox (4).
Separar hitbox (quem causa dano) e hurtbox (quem recebe dano) evita que o corpo físico do inimigo “seja o dano” e dá controle fino para ataques, invencibilidade e múltiplas zonas de acerto.
Criando uma área de dano com Area2D (hitbox/hurtbox)
Conceito: Area2D detecta sobreposição, não bloqueia movimento
Area2D é ideal para detecção: dano, coleta de itens, zonas de perigo, sensores. Ela não impede o movimento como um body sólido; ela apenas emite sinais quando algo entra/sai.
Passo a passo: Hitbox de ataque do Player
- No Player, adicione um filho
Area2DchamadoHitbox. - Dentro de
Hitbox, adicioneCollisionShape2D. - Escolha uma shape (geralmente
RectangleShape2Dpara um golpe “em caixa”, ouCapsuleShape2Dpara um golpe mais “arredondado”). - Posicione a hitbox à frente do personagem (ex.: no lado direito). Se o personagem virar, você pode espelhar a posição (ver exemplo de código abaixo).
- Configure Layers/Masks:
Hitboxna layer PlayerHitbox e mask EnemyHurtbox. - Desative a hitbox por padrão para não causar dano o tempo todo (ex.:
monitoring = falseoudisabledna shape).
Passo a passo: Hurtbox no inimigo
- No inimigo, adicione um filho
Area2DchamadoHurtbox. - Adicione
CollisionShape2De ajuste para cobrir a parte “atingível”. - Configure Layers/Masks:
Hurtboxna layer EnemyHurtbox e mask PlayerHitbox.
Conectando sinais para detectar contato (body_entered e area_entered)
Qual sinal usar?
body_entered(body: Node): quando um PhysicsBody2D entra na Area2D (ex.: Player entrando numa zona de perigo).area_entered(area: Area2D): quando uma Area2D entra em outra Area2D (ex.: Hitbox do player encostando na Hurtbox do inimigo).
Exemplo: Hurtbox do inimigo detectando a Hitbox do player (area_entered)
No nó Hurtbox (Area2D do inimigo), conecte o sinal area_entered para o script do inimigo (ou do próprio Hurtbox). Exemplo em GDScript:
extends Area2D @export var damage_receiver_path: NodePath var damage_receiver: Node func _ready() -> void: if damage_receiver_path != NodePath(): damage_receiver = get_node(damage_receiver_path) func _on_area_entered(area: Area2D) -> void: # Filtragem extra por grupo é opcional, mas ajuda na depuração if not area.is_in_group("player_hitbox"): return var dmg := 1 if area.has_method("get_damage"): dmg = area.get_damage() if damage_receiver and damage_receiver.has_method("apply_damage"): damage_receiver.apply_damage(dmg)Para isso funcionar bem:
- Adicione a Hitbox do player ao grupo
player_hitbox(Node > Groups). - Garanta que Layers/Masks estejam corretas (Hitbox enxerga Hurtbox e vice-versa).
Exemplo: Hitbox do player com dano configurável
No script da Hitbox (Area2D):
extends Area2D @export var damage: int = 1 func get_damage() -> int: return damageAtivando a hitbox apenas durante o ataque
Uma abordagem simples é ligar/desligar o monitoramento da área:
# No script do Player (exemplo) @onready var hitbox: Area2D = $Hitbox func start_attack() -> void: hitbox.monitoring = true func end_attack() -> void: hitbox.monitoring = falseSe preferir, você pode desabilitar a shape em vez do monitoring:
@onready var hitbox_shape: CollisionShape2D = $Hitbox/CollisionShape2D func start_attack() -> void: hitbox_shape.disabled = false func end_attack() -> void: hitbox_shape.disabled = trueEspelhando a posição da hitbox quando o player vira
Se você usa uma variável de direção (ex.: facing = 1 para direita e -1 para esquerda), pode reposicionar a hitbox:
@onready var hitbox: Area2D = $Hitbox @export var hitbox_offset: Vector2 = Vector2(18, 0) var facing: int = 1 func update_hitbox_side() -> void: hitbox.position = Vector2(hitbox_offset.x * facing, hitbox_offset.y)Recomendações de depuração (colisões, máscaras e testes)
1) Visualizar colisões no editor e em execução
- No editor 2D, selecione o nó e confira se a shape está realmente cobrindo a área correta.
- Durante o jogo, ative a visualização de colisões: em geral, você pode usar o menu Debug para habilitar a exibição de shapes/colisores (a opção exata pode variar por versão, mas procure por algo como “Visible Collision Shapes”).
2) Checar Layers/Masks (o erro mais comum)
- Se nada colide/detecta: verifique se a máscara inclui a camada do outro objeto.
- Se está colidindo com coisa errada: reduza a máscara para apenas o necessário.
- Em hitbox/hurtbox: confirme que você está usando
area_entered(Area com Area) e nãobody_entered.
3) Testes com múltiplos objetos
- Coloque 2 ou 3 inimigos próximos e teste se a hitbox acerta todos (ou apenas um, se essa for a regra do seu jogo).
- Teste hitbox encostando no cenário: ela não deveria “bater” no World se a máscara não incluir World.
- Teste tamanhos extremos: hitbox muito grande pode causar dano sem intenção; muito pequena pode falhar em contatos rápidos.
4) Logs rápidos para confirmar eventos
Durante a depuração, use prints temporários para confirmar se o sinal está disparando e qual objeto entrou:
func _on_area_entered(area: Area2D) -> void: print("Hurtbox tocada por: ", area.name, " layer/mask ok?")Se o print nunca aparece, o problema quase sempre é: shape ausente/desabilitada, monitoring desligado, ou layers/masks incompatíveis.