Voltar para o Blog
Quest Log

Como Fazer um Jogo 3D na Godot 4 (Passo a Passo)

Cena 3D estilizada com um personagem cápsula sobre uma plataforma, câmera e luzes de uma game engine

Como fazer um jogo 3D na Godot 4 do zero: monte a cena, mova um CharacterBody3D com WASD e pulo e ajuste a câmera, tudo em GDScript tipado, passo a passo.

Ferramenta:Godot

Fazer o primeiro jogo 3D no Godot assusta menos do que parece, e é exatamente isso que este guia de como fazer um jogo 3D no Godot 4 vai provar. A engine resolve o pesado (renderização, física, câmera) e sobra pra você o que importa: montar a cena, escrever o movimento e sentir o personagem andando pelo mundo. Nesse tutorial a gente sai do projeto vazio e chega num protótipo jogável: um personagem que anda com WASD, pula, e uma câmera em terceira pessoa que segue ele girando com o mouse.

Não precisa de nenhum asset. Tudo aqui usa as formas primitivas da própria engine, então você pode focar 100% na lógica. Todo código é GDScript do Godot 4.x e roda como está.

Uma coisa antes de começar: se você nunca abriu o Godot, vale dez minutos num projeto 2D qualquer só pra se acostumar com a ideia de cena e node. Mas se você já sabe que cena é uma árvore de nodes, pode seguir direto.

Criando o projeto e a cena 3D

Crie um projeto novo e escolha o renderer Forward+, que é o padrão pra desktop e o que entrega mais qualidade visual. Se o alvo fosse mobile ou web, a escolha seria Mobile ou Compatibility, mas pro primeiro jogo 3D fique no Forward+. Quando quiser colocar esse jogo pra rodar no navegador, o Compatibility é o caminho, e o guia de como exportar um jogo da Godot para web em HTML5 mostra o processo do começo ao fim.

Crie a cena principal com um node raiz Node3D e salve como main.tscn. É nela que vamos montar o mundo.

O chão

O chão precisa de duas coisas: aparência e colisão. A estrutura clássica é um StaticBody3D com uma malha e uma shape:

Chao (StaticBody3D)
├── MeshInstance3D    (BoxMesh, ex: 20 x 1 x 20)
└── CollisionShape3D  (BoxShape3D do mesmo tamanho)

No MeshInstance3D, crie um BoxMesh na propriedade Mesh e ajuste o Size pra algo como 20, 1, 20. No CollisionShape3D, crie um BoxShape3D com o mesmo tamanho. Se a malha e a shape ficarem com tamanhos diferentes, o personagem vai flutuar ou afundar no chão, então confira os dois.

Dica de prototipagem: os nodes CSGBox3D (e os outros CSG) fazem malha e colisão de uma vez, basta ligar a propriedade Use Collision. Pra blocar um nível de teste em cinco minutos, eles são imbatíveis. O custo de performance só vira problema em cena grande, o que não é o caso aqui.

Luz e céu

Cena 3D sem luz é um breu. Adicione dois nodes na raiz:

  • DirectionalLight3D: o "sol" da cena. Rotacione ele pra apontar pra baixo em diagonal e ligue Shadow > Enabled. Sombra é o que faz o cérebro entender onde as coisas estão no espaço, ela vale o custo.
  • WorldEnvironment: crie um Environment novo na propriedade, mude o Background > Mode pra Sky e crie um Sky com material ProceduralSkyMaterial. Pronto, você tem céu e iluminação ambiente decente sem baixar nada.

Esse trio (chão, luz direcional, céu procedural) é o esqueleto de praticamente toda cena 3D de protótipo. Aperte F6 pra rodar a cena: vai dar erro de câmera, e é o que vamos resolver agora, junto com o player.

O player: CharacterBody3D, colisão e câmera

Pra personagem controlado por código, o node certo é o CharacterBody3D. Ele não é simulado pela física como um RigidBody: você dita a velocidade e ele resolve as colisões deslizando nas superfícies, que é exatamente o comportamento que um player precisa.

Crie uma cena nova com essa estrutura e salve como player.tscn:

Player (CharacterBody3D)
├── MeshInstance3D        (CapsuleMesh)
├── CollisionShape3D      (CapsuleShape3D)
└── CameraPivot (Node3D)
    └── SpringArm3D
        └── Camera3D

Cada peça tem um motivo:

  • CapsuleShape3D é a melhor shape pra personagem. A base arredondada sobe pequenos desníveis e desliza em quinas sem travar, coisa que uma caixa não faz.
  • CameraPivot é um Node3D vazio que serve de "pescoço": girar ele no eixo Y gira a câmera ao redor do personagem.
  • SpringArm3D é um braço retrátil. A câmera fica na ponta dele, e quando uma parede entra entre a câmera e o player, o braço encolhe sozinho pra câmera não atravessar a parede. Esse node resolve de graça um dos problemas mais chatos desse tipo de câmera, e dá pra ir bem além do básico: o guia de câmera em terceira pessoa com SpringArm3D destrincha esse setup em detalhe.

Posicione o CameraPivot na altura da cabeça (Y em torno de 1,5) e configure o SpringArm3D com Spring Length de 4 ou 5. Ele estica no eixo -Z local, então a câmera filha já fica atrás do pivot naturalmente.

Mapeando o WASD no Input Map

Antes do script, registre as ações de input. Em Project Settings > Input Map, crie cinco ações e associe as teclas:

  • frente → W
  • tras → S
  • esquerda → A
  • direita → D
  • pular → Espaço

Usar ações em vez de teclas direto no código não é burocracia: é o que permite trocar o mapeamento depois (ou suportar controle) sem tocar uma linha de script.

Curso de Godot
Quer fazer seu primeiro jogo na Godot?

No curso de Godot da CursoGame.Dev você vai do zero ao primeiro jogo, com um desafio prático em cada level e suporte individual no WhatsApp quando travar.

Conhecer o curso de Godot
Suporte no WhatsAppAcesso vitalícioGarantia de 7 dias

Movimento WASD do seu jogo 3D no Godot

Agora o script. Anexe ao node Player:

extends CharacterBody3D

const SPEED = 5.0
const JUMP_VELOCITY = 4.5
const MOUSE_SENSITIVITY = 0.003

@onready var pivot = $CameraPivot
@onready var spring_arm: SpringArm3D = $CameraPivot/SpringArm3D

var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")

func _ready() -> void:
    Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
    # Impede o braço da câmera de colidir com o próprio player.
    spring_arm.add_excluded_object(get_rid())

func _input(event) -> void:
    if event is InputEventMouseMotion and Input.mouse_mode == Input.MOUSE_MODE_CAPTURED:
        # Mouse pros lados gira o pivot inteiro no eixo Y.
        pivot.rotate_y(-event.relative.x * MOUSE_SENSITIVITY)
        # Mouse pra cima/baixo inclina só o braço, com trava pra não capotar.
        spring_arm.rotation.x = clamp(
            spring_arm.rotation.x - event.relative.y * MOUSE_SENSITIVITY,
            -1.2, 0.3
        )
    if event.is_action_pressed("ui_cancel"):
        Input.mouse_mode = Input.MOUSE_MODE_VISIBLE

func _physics_process(delta: float) -> void:
    if not is_on_floor():
        velocity.y -= gravity * delta

    if Input.is_action_just_pressed("pular") and is_on_floor():
        velocity.y = JUMP_VELOCITY

    var input_dir = Input.get_vector("esquerda", "direita", "frente", "tras")
    # Transforma o input 2D em direção 3D relativa pra onde a câmera aponta.
    var direction = (pivot.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()

O script é curto, mas três pontos merecem explicação porque são onde iniciante trava.

Todo movimento vive no _physics_process. Esse callback roda em passo fixo (60 vezes por segundo por padrão), independente do FPS da máquina. Movimento no _process varia com o framerate e dessincroniza da física, gerando tremor. Regra simples: mexeu em velocity ou posição de corpo físico, é _physics_process.

A gravidade é manual. CharacterBody3D não cai sozinho, você soma a gravidade na velocidade a cada frame de física. Repare que no 3D ela é subtraída (velocity.y -= ...), porque o eixo Y aponta pra cima. É o oposto do 2D, e é o bug mais clássico de quem migra de um pro outro.

A direção é relativa à câmera. O Input.get_vector() devolve um Vector2 onde apertar W dá Y negativo, porque no 3D do Godot "frente" é o -Z. Multiplicar esse vetor pela pivot.basis rotaciona o input pro referencial da câmera: apertar W sempre move pra onde você está olhando, que é o comportamento esperado num jogo em terceira pessoa. Sem essa multiplicação, W moveria sempre pro norte do mundo, não importa pra onde a câmera aponte.

Mouse capturado é o detalhe de qualidade de vida: MOUSE_MODE_CAPTURED prende e esconde o cursor pra câmera girar livre, e o ESC (ui_cancel, que já vem mapeado de fábrica) solta o mouse pra você conseguir fechar a janela em paz.

Instancie o player.tscn dentro da main.tscn (arraste o arquivo da aba FileSystem pra viewport), suba ele um pouco no eixo Y pra não nascer dentro do chão, e rode com F5 definindo a main como cena principal. Você tem um personagem andando, pulando e uma câmera orbitando. Isso já é um jogo 3D funcionando.

Dando um objetivo: moedas com Area3D

Andar pelo mundo é legal por uns dois minutos. Jogo precisa de objetivo, e o mais barato de implementar é coletável. Pra detectar "o player encostou aqui" sem colisão física, o node certo é o Area3D.

Crie a cena moeda.tscn:

Moeda (Area3D)
├── MeshInstance3D    (CylinderMesh achatado, ou TorusMesh)
└── CollisionShape3D  (CylinderShape3D)

E o script:

extends Area3D

signal coletada

func _ready() -> void:
    body_entered.connect(_on_body_entered)

func _process(delta: float) -> void:
    # Gira no próprio eixo. Rotação é visual, então _process serve.
    rotate_y(2.0 * delta)

func _on_body_entered(body) -> void:
    if body.name == "Player":
        coletada.emit()
        queue_free()

O sinal body_entered dispara quando um corpo físico entra na área. A checagem por nome funciona pro protótipo; num projeto maior você usaria grupos (body.is_in_group("player")), que aguentam renomear nodes sem quebrar nada.

O sinal coletada fica emitido pra quem quiser ouvir: um script na cena principal pode conectar cada moeda a um contador e mostrar num Label. Espalhe dez moedas pela cena (duplicar com Ctrl+D é seu amigo), e de repente existe um loop de gameplay: vá até ali, pegue aquilo.

Onde esse protótipo vira jogo

Com personagem, câmera e coletável funcionando, você tem a base de um 3D platformer, o esqueleto de um jogo de plataforma 3D no Godot completo. O caminho natural a partir daqui, em ordem de retorno por esforço:

  1. Nível de verdade. Empilhe CSGBox3D criando plataformas em alturas diferentes. Esse é o começo do blockout, e o guia de CSG para prototipar cenários 3D mostra como cavar portas, montar salas e testar o nível inteiro só com formas simples antes de modelar qualquer arte. Pular entre plataformas testa o controle de um jeito que andar no plano não testa, e você vai sentir na hora se a gravidade e a força do pulo estão boas.
  2. Queda e respawn. Um Area3D gigante abaixo do mapa que devolve o player pro início quando ele cai. Três linhas de código e o nível passa a ter risco.
  3. Tuning do movimento. SPEED, JUMP_VELOCITY e a gravidade do projeto não têm valor "correto". Roda, sente, ajusta. Esse ciclo é o trabalho real de game feel, e os valores que funcionam pro seu jogo só aparecem testando.
  4. Um modelo de verdade. Quando cansar da cápsula, importe um glTF (o Godot lê nativamente) e coloque no lugar do MeshInstance3D. Se quiser fazer isso do jeito certo, o guia de Blender para Godot mostra como exportar e importar o modelo sem quebrar escala nem material, ou aprenda a criar os próprios modelos com o guia de Blender para desenvolvimento de jogos. A lógica não muda nada.
  5. Um segundo jogador no sofá. Com o player e a câmera já encapsulados numa cena, duplicar tudo pra um multiplayer local com tela dividida (split screen) no Godot é mais simples do que parece: cada jogador ganha sua própria viewport e câmera, e o movimento que você acabou de escrever é reaproveitado sem mudança.
  6. Som que vem do lugar certo. Quando quiser que passos, inimigos e objetos soem vindo da posição deles no espaço, e não "direto no ouvido", veja áudio 3D posicional na Godot. É o que transforma um cenário mudo num mundo que parece vivo.
  7. Um mundo de blocos. Se a sua ideia de 3D é terreno editável, o degrau seguinte é fazer um jogo estilo Minecraft na Godot com GridMap: terreno gerado por noise e blocos que o jogador coloca e quebra em primeira pessoa.

Fechando

O primeiro jogo 3D no Godot se resume a uma cena com chão, luz e céu, um CharacterBody3D com cápsula, um SpringArm3D segurando a câmera e umas 60 linhas de GDScript. Nenhuma peça dessas é difícil sozinha, o que confunde é não saber quais peças existem e como se encaixam. Agora você sabe. E se você vem do .NET e prefere escrever a mesma lógica em C#, dá pra fazer todo esse fluxo na versão .NET da engine: veja como usar C# na Godot.

O erro que eu mais vejo nessa fase é pular pra modelagem, shader e asset bonito antes do movimento estar gostoso. Resista. Personagem de cápsula com controle bom é um jogo melhor que personagem lindo com controle ruim, e o controle você acabou de construir. Itera nele primeiro, o resto é troca de visual.

Vale saber que a física dos seus corpos 3D é calculada pelo Jolt: entenda o que é isso no post sobre o Jolt Physics 5.6 na Godot. E se o seu projeto é 2D em vez de 3D, o mesmo raciocínio de cena e script vale: veja como fazer um jogo 2D na Godot. Se ainda está decidindo a engine pra esse projeto 2D, compare as opções no guia de Godot e GameMaker, e se a dúvida é entre as duas engines mais populares, o comparativo completo entre Godot e Unity ajuda a decidir com calma. E quando o jogo começar a tomar forma, configure a janela do jogador com o guia de configurações de vídeo, resolução e tela cheia na Godot.

Perguntas frequentes

Como fazer um jogo 3D no Godot sendo iniciante?

Comece por um protótipo sem assets: um chão de BoxMesh, um CharacterBody3D de cápsula, uma DirectionalLight3D e uma câmera com SpringArm3D. Com isso e uns 60 linhas de GDScript você tem personagem andando, pulando e câmera orbitando com o mouse. É exatamente o passo a passo deste tutorial, e dá pra completar numa tarde.

O Godot é bom para jogos 3D?

Para 3D indie e estilizado, sim: a linha 4.x trouxe renderizador moderno (Vulkan, Metal, D3D12), física com Jolt e iluminação global em evolução. Para fotorrealismo de ponta, Unity e Unreal ainda têm mais ferramenta pronta. A prática de muitos jogos comerciais mostra que o teto do 3D da Godot é bem mais alto do que a fama sugere.

Qual renderer escolher no projeto 3D: Forward+, Mobile ou Compatibility?

Para desktop, Forward+, que é o padrão e entrega a melhor qualidade visual. Mobile prioriza performance em celular e Compatibility mira hardware fraco e web. Dá pra trocar depois nas configurações do projeto, então a escolha inicial não te prende.

Preciso saber 2D antes de fazer 3D no Godot?

Não é obrigatório, mas ajuda: os conceitos de cena, node e sinal são os mesmos, e no 2D você aprende com menos variáveis na mesa. Se você nunca abriu a engine, vale dez minutos num projeto 2D só pra entender a árvore de cenas antes de encarar câmera e espaço 3D.

Que node usar para o personagem 3D: CharacterBody3D ou RigidBody3D?

Para personagem controlado pelo jogador, CharacterBody3D: você dita a velocidade e ele resolve colisões deslizando nas superfícies. RigidBody3D é para objetos simulados pela física (caixas, bolas, destroços), onde quem manda é o motor de física, não o input do jogador.