Física de Jogos no Godot: Tutorial Completo de CharacterBody e RigidBody

Domine física de jogos no Godot Engine. Tutorial completo sobre CharacterBody2D/3D, RigidBody, colisões, raycasting e otimização de performance.
Índice do Conteúdo
Artigos Relacionados

C# vs GDScript no Godot: Qual Linguagem Escolher em 2025?
01/10/2025

Multiplayer no Godot: Tutorial Completo de Networking Para Iniciantes
01/10/2025

Como Criar Seu Primeiro Jogo Mobile em 2025: Guia Completo Android e iOS
01/10/2025

Como Fazer Um Jogo do Zero: Guia Completo Para Iniciantes em 2025
01/10/2025

Design de Levels: Princípios e Práticas Para Criar Níveis Memoráveis
01/10/2025
Física de Jogos no Godot: Tutorial Completo de CharacterBody e RigidBody
A física é o coração de como jogos se sentem ao jogar. Pulo responsivo, colisões satisfatórias e movimento natural separam jogos amadores de experiências polidas e profissionais. No Godot Engine, o sistema de física oferece poder e flexibilidade incríveis - mas também pode confundir iniciantes.
Com o Godot 4.x, o sistema de física foi significativamente melhorado, trazendo interpolação nativa, melhor performance e APIs mais intuitivas. Nodes como CharacterBody2D/3D e RigidBody2D/3D fornecem fundação sólida para implementar movimento, colisões e interações físicas.
Neste tutorial completo, vou te guiar desde os conceitos fundamentais de física no Godot até implementações avançadas. Você aprenderá a diferença entre CharacterBody e RigidBody, como implementar movimento suave, gerenciar colisões, usar raycasting e otimizar performance. Ao final, você terá conhecimento profundo para criar qualquer tipo de movimento e interação física no seu jogo.
Fundamentos de Física no Godot
Antes de escrever código, é essencial entender como o Godot estrutura física.
O Sistema de Physics Engine
Godot usa engines de física separadas para 2D e 3D:
2D Physics (GodotPhysics2D):
- Engine própria otimizada para jogos 2D
- Eixos X e Y apenas
- Gravity padrão: (0, 980) pixels/s²
3D Physics (GodotPhysics3D ou Jolt Physics):
- Godot 4.5 introduziu Jolt Physics como alternativa
- GodotPhysics3D mantido por compatibilidade
- Jolt oferece melhor performance e estabilidade
- Gravity padrão: (0, -9.8, 0) metros/s²
Physics Process vs Regular Process:
func _process(delta):
# Roda cada frame (variável)
# Use para visual updates, input, etc.
pass
func _physics_process(delta):
# Roda em fixed timestep (padrão: 60 FPS)
# SEMPRE use para física e movimento
pass
Por que _physics_process?
- Timestep fixo garante comportamento consistente
- Physics engine sincronizado com este loop
- Movimentos em _process() podem causar jittering
Tipos de Physics Bodies
Godot oferece vários tipos de bodies para diferentes propósitos:
StaticBody2D/3D
- Não se move (paredes, chão, obstáculos fixos)
- Colide com outros bodies mas permanece imóvel
- Performance máxima (engine otimiza agressivamente)
CharacterBody2D/3D
- Movimento controlado via script (player, AI enemies)
- Método para movimento com colisão
move_and_slide()
- Use para qualquer personagem controlável
RigidBody2D/3D
- Simulação física completa (caixas, barris, ragdolls)
- Engine calcula movimento baseado em forças
- Use para objetos que respondem a física realista
AnimatableBody2D/3D
- Kinematic bodies com animação
- Para plataformas móveis, elevadores
- Movem-se via animation ou script mas não respondem a forças
Area2D/3D
- Não colide fisicamente
- Detecta overlaps e triggers
- Use para zones, triggers, pickups
Shapes de Colisão
Bodies precisam de shapes para definir área de colisão:
Tipos de shapes:
- RectangleShape2D/BoxShape3D: Retângulos/caixas (mais comum)
- CircleShape2D/SphereShape3D: Círculos/esferas (bom para projéteis)
- CapsuleShape2D/3D: Cápsula (ideal para personagens)
- ConvexPolygonShape/ConcavePolygonShape: Shapes customizadas
Dica importante: Shapes simples são muito mais performáticas. Use combinação de shapes simples em vez de uma shape complexa quando possível.
Descubra Seu Potencial em Game Development
Física de jogos é apenas uma das muitas habilidades em game dev. Você prefere trabalhar com sistemas técnicos como física e IA, ou é mais criativo focando em arte e design? Descubra seu perfil ideal.
CharacterBody2D: Movimento de Personagem
CharacterBody é o node mais usado para personagens controláveis. Vou guiar você pela implementação completa.
Setup Básico
Estrutura de nodes:
Player (CharacterBody2D)
├── CollisionShape2D
└── Sprite2D
Script básico:
extends CharacterBody2D
const SPEED = 300.0
const JUMP_VELOCITY = -400.0
# Get the gravity from the project settings
var gravity = ProjectSettings.get_setting("physics/2d/default_gravity")
func _physics_process(delta):
# Apply gravity
if not is_on_floor():
velocity.y += gravity * delta
# Handle jump
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get input direction
var direction = Input.get_axis("ui_left", "ui_right")
# Apply movement
if direction:
velocity.x = direction * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
move_and_slide()
Entendendo move_and_slide()
move_and_slide()
- Move o body baseado em
velocity
- Detecta e resolve colisões automaticamente
- Slides ao longo de superfícies
- Retorna true se houve colisão
Parâmetros importantes:
# Godot 4.x sintaxe (simplificada vs 3.x)
move_and_slide()
# Acesse informações após o movimento:
is_on_floor() # Está no chão?
is_on_ceiling() # Bateu no teto?
is_on_wall() # Tocando parede?
get_slide_collision_count() # Número de colisões
get_slide_collision(index) # Detalhes da colisão
Movimento Suave e Aceleração
Movimento instantâneo parece robótico. Adicione aceleração:
extends CharacterBody2D
const SPEED = 300.0
const ACCELERATION = 2000.0 # Aceleração
const FRICTION = 1500.0 # Desaceleração
func _physics_process(delta):
var direction = Input.get_axis("ui_left", "ui_right")
if direction:
# Acelera gradualmente
velocity.x = move_toward(velocity.x, direction * SPEED, ACCELERATION * delta)
else:
# Desacelera com fricção
velocity.x = move_toward(velocity.x, 0, FRICTION * delta)
move_and_slide()
Dica: Valores maiores de ACCELERATION = resposta mais rápida. Ajuste ao sentir o jogo.
Pulo Variável (Jump Buffering)
Players esperam controle preciso sobre altura do pulo:
const JUMP_VELOCITY = -400.0
const JUMP_CUT_MULTIPLIER = 0.5 # Reduz velocidade ao soltar
func _physics_process(delta):
# Gravity normal
if not is_on_floor():
velocity.y += gravity * delta
# Pulo normal
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Cortar pulo se soltar botão
if Input.is_action_just_released("jump") and velocity.y < 0:
velocity.y *= JUMP_CUT_MULTIPLIER
move_and_slide()
Coyote Time e Jump Buffering
Faça pulo sentir mais responsivo:
Coyote Time: Player pode pular poucos frames após sair da plataforma Jump Buffering: Pressionar pulo poucos frames antes de pousar funciona
var coyote_time = 0.1 # Segundos de "grace period"
var coyote_timer = 0.0
var jump_buffer_time = 0.1
var jump_buffer_timer = 0.0
func _physics_process(delta):
# Atualiza coyote timer
if is_on_floor():
coyote_timer = coyote_time
else:
coyote_timer -= delta
# Atualiza jump buffer
if Input.is_action_just_pressed("jump"):
jump_buffer_timer = jump_buffer_time
else:
jump_buffer_timer -= delta
# Pulo com coyote time e buffer
if jump_buffer_timer > 0 and coyote_timer > 0:
velocity.y = JUMP_VELOCITY
jump_buffer_timer = 0
coyote_timer = 0
move_and_slide()
Essas pequenas features fazem diferença ENORME no game feel.
CharacterBody3D: Movimento First-Person
Movimento 3D adiciona dimensão Z e rotação de câmera.
FPS Controller Básico
extends CharacterBody3D
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
const SENSITIVITY = 0.003 # Mouse sensitivity
@onready var camera = $Camera3D
var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
func _ready():
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
func _input(event):
# Mouse look
if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
rotate_y(-event.relative.x * SENSITIVITY)
camera.rotate_x(-event.relative.y * SENSITIVITY)
camera.rotation.x = clamp(camera.rotation.x, -PI/2, PI/2)
func _physics_process(delta):
# Gravity
if not is_on_floor():
velocity.y -= gravity * delta
# Jump
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Movement
var input_dir = Input.get_vector("move_left", "move_right", "move_forward", "move_back")
var direction = (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
RigidBody: Simulação Física
Para objetos que respondem a física realista, use RigidBody.
Setup de RigidBody2D
extends RigidBody2D
func _ready():
# Propriedades físicas
mass = 10.0
gravity_scale = 1.0 # 1.0 = gravity normal
linear_damp = 0.1 # Air resistance
angular_damp = 0.5 # Rotational resistance
func apply_force_example():
# Aplicar força
apply_central_impulse(Vector2(500, -500)) # Impulso instantâneo
apply_force(Vector2(100, 0)) # Força contínua
func _integrate_forces(state):
# Para controle manual avançado
# state.linear_velocity = ...
# state.transform.origin = ...
pass
Diferença: Impulse vs Force
Impulse:
- Mudança instantânea de velocidade
- Use para: explosões, pulo, colisões
Force:
- Aplicada continuamente
- Use para: motores, vento, magnetismo
# Impulse - instantâneo
apply_central_impulse(Vector2(500, 0))
# Force - contínuo (chamar em _physics_process)
func _physics_process(delta):
apply_central_force(Vector2(100, 0))
Lock de Rotação
Às vezes você quer física mas sem rotação:
extends RigidBody2D
func _ready():
lock_rotation = true # Impede rotação
Sleeping e Continuous CD
Sleeping: RigidBodies "dormem" quando param de se mover (otimização). Acordam quando interagem.
# Forçar acordar
sleeping = false
# Prevenir dormir
can_sleep = false # Use com cautela (impacto performance)
Continuous Collision Detection: Para objetos rápidos que atravessam paredes:
continuous_cd = CCD_MODE_CAST_RAY # Previne tunneling
Colisões Avançadas
Layers e Masks
Controle o que colide com o quê:
Collision Layer: "Eu estou nesta(s) layer(s)" Collision Mask: "Eu colido com esta(s) layer(s)"
Exemplo:
Layer 1: Player
Layer 2: Enemies
Layer 3: Walls
Layer 4: Pickups
Player:
- Layer: 1
- Mask: 2, 3, 4 (colide com enemies, walls, pickups)
Enemy:
- Layer: 2
- Mask: 1, 3 (colide com player e walls)
Pickup:
- Layer: 4
- Mask: nenhum (não colide fisicamente, usa Area2D)
Em código:
# Setar layer (bit shifting)
collision_layer = 1 # Layer 1
collision_mask = 6 # Layers 2 e 3 (2 + 4 = 6)
# Verificar layer
if collision_layer & (1 << 0): # Está na layer 1?
pass
Detecting Colisões
CharacterBody:
move_and_slide()
for i in get_slide_collision_count():
var collision = get_slide_collision(i)
print("Colidiu com: ", collision.get_collider().name)
print("Normal: ", collision.get_normal())
print("Posição: ", collision.get_position())
RigidBody:
func _on_body_entered(body):
print("Colidiu com: ", body.name)
func _on_body_exited(body):
print("Parou de colidir com: ", body.name)
Area2D (triggers):
func _on_area_entered(area):
print("Overlap com area: ", area.name)
func _on_body_entered(body):
if body.name == "Player":
# Player entrou na trigger zone
trigger_event()
Raycasting
Raycasts detectam objetos em linha reta sem física real.
RayCast2D Node
extends Node2D
@onready var raycast = $RayCast2D
func _physics_process(delta):
if raycast.is_colliding():
var collider = raycast.get_collider()
var point = raycast.get_collision_point()
var normal = raycast.get_collision_normal()
print("Raycast detectou: ", collider.name, " em ", point)
Configuração no Inspector:
- Enabled: true
- Target Position: Para onde o ray aponta (relativo)
- Collision Mask: O que detectar
Raycast via Código (PhysicsRayQueryParameters)
Mais flexível que RayCast2D node:
func raycast_from_point(from: Vector2, to: Vector2) -> Dictionary:
var space_state = get_world_2d().direct_space_state
var query = PhysicsRayQueryParameters2D.create(from, to)
query.collision_mask = 1 # Layer 1
var result = space_state.intersect_ray(query)
if result:
print("Hit: ", result.collider.name)
print("Position: ", result.position)
print("Normal: ", result.normal)
return result
Casos de uso:
- Line of sight: Inimigo vê player?
- Shooting: Onde bala acerta?
- Ground check: Player está no chão? (alternativa a is_on_floor)
ShapeCast (Raycast com Shape)
Godot 4.x introduziu ShapeCast - raycast com forma geométrica:
@onready var shapecast = $ShapeCast2D
func _physics_process(delta):
if shapecast.is_colliding():
# Detecta colisões ao longo de um shape móvel
pass
Útil para detectar objetos em área enquanto se move.
Domine Godot e Construa Jogos Profissionais
Física é apenas uma peça do puzzle. Jogos completos requerem arte, áudio, UI, design de levels e muito mais. Aprenda todas as disciplinas necessárias para criar e publicar jogos de sucesso.
One-Way Platforms (Plataformas Descíveis)
Plataformas que você pode pular através mas cair em cima:
extends CharacterBody2D
func _physics_process(delta):
# Movimento normal
velocity.y += gravity * delta
# Detectar input para descer
if Input.is_action_pressed("ui_down") and is_on_floor():
position.y += 2 # Pequeno deslocamento para baixo
move_and_slide()
No OneWayCollision node:
- Configure Collision Layer/Mask
- Set property to true
one_way_collision
- Set (pixels de margem)
one_way_collision_margin
Plataformas Móveis
Para plataformas que se movem e carregam o player:
Usando AnimatableBody2D:
extends AnimatableBody2D
@export var move_distance = 200.0
@export var move_speed = 100.0
var start_pos: Vector2
var target_pos: Vector2
var direction = 1
func _ready():
start_pos = position
target_pos = start_pos + Vector2(move_distance, 0)
func _physics_process(delta):
if direction == 1:
position.x += move_speed * delta
if position.x >= target_pos.x:
direction = -1
else:
position.x -= move_speed * delta
if position.x <= start_pos.x:
direction = 1
Importante: CharacterBody automaticamente "gruda" em AnimatableBody em movimento (desde que is_on_floor() seja true).
Otimização de Performance
Física pode ser cara computacionalmente. Aqui estão técnicas de otimização:
1. Use Shapes Simples
# BOM: Shape simples
var shape = CircleShape2D.new()
# RUIM: Polygon complexo
var shape = ConcavePolygonShape2D.new()
Sempre prefira círculos, retângulos e cápsulas.
2. Collision Layers Inteligentes
Reduza checks desnecessários:
- Projéteis não precisam colidir entre si
- Pickups não precisam colidir com pickups
3. Sleeping de RigidBodies
Permita RigidBodies dormirem quando não estão em uso:
can_sleep = true # Default, mas garanta que está true
4. Reduza Physics Ticks Se Possível
Em Project Settings:
- : Padrão 60
Physics/Common/Physics_ticks_per_second
- Reduzir para 30 ou 45 em jogos mobile menos exigentes
5. Use Area2D Para Triggers
Area2D é mais leve que collision detection física real:
# Use Area2D para:
# - Trigger zones
# - Pickup detection
# - Damage areas
# Use CollisionShape2D para:
# - Actual physical collision
# - Movement blocking
6. Desabilite Physics Quando Fora da Tela
extends RigidBody2D
func _on_visible_on_screen_notifier_screen_exited():
sleeping = true # Otimiza quando off-screen
func _on_visible_on_screen_notifier_screen_entered():
sleeping = false
Debugging de Física
Visible Collision Shapes
No editor: Debug > Visible Collision Shapes (ON)
Mostra todos collision shapes durante gameplay - essencial para debug.
Draw Raycasts
func _process(delta):
# Draw ray visualmente (debug)
queue_redraw()
func _draw():
if raycast.is_colliding():
draw_line(Vector2.ZERO, raycast.get_collision_point() - global_position, Color.RED, 2)
Performance Monitor
No editor: Debug > Performance Monitor
Monitore:
- 2D/3D physics time
- Collision objects count
- Active bodies
Se physics time > 16ms (60 FPS), há problemas de performance.
Conclusão: Física Sólida = Jogo Satisfatório
Física bem implementada é invisível mas essencial. Players não notam boa física - mas definitivamente notam física ruim.
Recapitulando conceitos essenciais:
- ✅ Use para qualquer código relacionado a física
_physics_process()
- ✅ CharacterBody para personagens controlados, RigidBody para objetos físicos
- ✅ é seu melhor amigo para movimento de personagem
move_and_slide()
- ✅ Adicione aceleração, coyote time e jump buffering para game feel excelente
- ✅ Use collision layers/masks para controlar o que interage com o quê
- ✅ Raycasts são versáteis para line of sight, shooting, ground checking
- ✅ Otimize agressivamente - física pode ser cara
Seu próximo passo:
Abra Godot e implemente movimento de personagem do zero. Comece simples:
- Dia 1: Movimento horizontal básico
- Dia 2: Adicione pulo e gravidade
- Dia 3: Implemente aceleração suave
- Dia 4: Adicione coyote time e jump buffering
- Dia 5: Polish e teste extensivamente
Física é ciência e arte. A ciência você acabou de aprender. A arte vem de testar, ajustar, e sentir o que funciona.
Agora vá criar movimento que seja satisfatório, responsivo e divertido. Seu jogo merece física excelente.
Índice do Conteúdo
Artigos Relacionados

C# vs GDScript no Godot: Qual Linguagem Escolher em 2025?
01/10/2025

Multiplayer no Godot: Tutorial Completo de Networking Para Iniciantes
01/10/2025

Como Criar Seu Primeiro Jogo Mobile em 2025: Guia Completo Android e iOS
01/10/2025

Como Fazer Um Jogo do Zero: Guia Completo Para Iniciantes em 2025
01/10/2025

Design de Levels: Princípios e Práticas Para Criar Níveis Memoráveis
01/10/2025