Voltar para o Blog
Quest Log

GDScript do Zero: A Linguagem do Godot na Prática

Editor de código do Godot exibindo um script GDScript ao lado da árvore de cena

Aprenda GDScript do zero: sintaxe, variáveis, tipos, funções e seu primeiro script rodando no Godot 4. Tutorial prático para quem nunca programou na vida.

GDScript do Zero: A Linguagem do Godot na Prática

Se você nunca programou na vida e quer fazer jogos no Godot, aprender GDScript do zero é o caminho mais curto que existe. A linguagem foi desenhada pra engine, então não tem camada de configuração, não tem projeto separado, não tem build demorado: você escreve, aperta F5 e vê o resultado. Esse tutorial cobre exatamente o que você precisa pro primeiro script: sintaxe, variáveis, tipos, funções e um node se mexendo na tela.

Uma coisa antes de começar: você não precisa "aprender programação" inteira antes de fazer jogo. Você precisa de um subconjunto pequeno de conceitos, e todos eles cabem aqui. O resto você pega conforme o jogo pede.

O que é GDScript e por que começar por ele

GDScript é a linguagem de script nativa do Godot. A sintaxe lembra Python: blocos definidos por indentação, pouca cerimônia, código que dá pra ler em voz alta. Mas ela não é Python, é uma linguagem própria, integrada na engine, com tipos como Vector2 e funções como _ready() que existem porque jogo precisa delas.

O Godot também aceita C#, e a pergunta "qual eu uso?" aparece sempre. Minha resposta pra quem está começando: GDScript, sem dúvida. O editor de código vem embutido, o autocomplete conhece toda a API da engine, a documentação abre dentro do próprio Godot, e a iteração é instantânea. C# faz sentido mais tarde, em sistema pesado de cálculo ou quando você já vem do .NET. Pra aprender, a fricção menor ganha.

Onde o código vive: scripts e nodes

No Godot, tudo na cena é um node: o personagem, a câmera, o texto na tela. Um script é um arquivo .gd que você anexa a um node pra dar comportamento a ele. O script sempre começa dizendo de qual tipo de node ele estende:

extends Node2D

func _ready():
    print("esse node acabou de entrar na cena")

Duas coisas pra reparar. Primeiro, o _ready(): é uma função que a engine chama sozinha quando o node entra na cena. Você não chama ela, o Godot chama. Segundo, a indentação: o print está deslocado pra dentro porque pertence à função. Em GDScript, indentação não é estética, é o que define onde um bloco começa e termina. Misturar tab com espaço dá erro, então deixe o editor do Godot cuidar disso (ele usa tab por padrão).

Pra testar: crie uma cena com um Node2D, clique no ícone de pergaminho pra anexar um script, cole o código acima e rode. A mensagem aparece no painel Output. Pronto, você executou seu primeiro GDScript.

GDScript do zero: variáveis e tipos

Variável é um nome que guarda um valor. Em GDScript você declara com var:

var vida = 100
var nome_do_jogador = "Ada"
var velocidade = 250.5
var esta_vivo = true

Esses quatro exemplos já mostram os tipos básicos:

  • int: número inteiro (100, -3)
  • float: número com casa decimal (250.5)
  • String: texto, sempre entre aspas ("Ada")
  • bool: verdadeiro ou falso (true, false)

Pra valor que nunca muda, use const. Se o código tentar alterar, o Godot acusa erro antes mesmo de rodar:

const GRAVIDADE = 980.0

Além dos básicos, dois tipos de coleção aparecem o tempo todo:

# Array: lista ordenada, acessada por posição (começa em 0).
var inventario = ["espada", "poção", "mapa"]
print(inventario[0])        # espada
inventario.append("chave")  # adiciona no fim

# Dictionary: pares de chave e valor.
var atributos = {"forca": 12, "agilidade": 8}
print(atributos["forca"])   # 12
atributos["sorte"] = 5      # cria uma chave nova

E o tipo mais "de jogo" de todos, o Vector2, que guarda um par X e Y. Posição, direção e velocidade em 2D são tudo Vector2:

var posicao = Vector2(100, 50)
print(posicao.x)  # 100.0

Tipagem dinâmica e estática

GDScript deixa você escolher. No modo dinâmico (os exemplos acima), a variável aceita qualquer tipo. No modo estático, você declara o tipo e o Godot te avisa na hora se algo não bate:

var vida: int = 100
var nome: String = "Ada"
var velocidade := 250.5  # := infere o tipo (float) pelo valor

Minha recomendação, mesmo pra iniciante: use os dois-pontos desde o começo. O autocomplete fica muito melhor, os erros aparecem enquanto você digita em vez de no meio do jogo rodando, e em Godot 4 código tipado executa mais rápido. Custa dois caracteres e te poupa horas de caça a bug.

Funções: dando nome a um pedaço de lógica

Função é um bloco de código com nome, que você escreve uma vez e chama quantas vezes quiser. Declara com func:

func causar_dano(quantidade: int) -> void:
    vida -= quantidade
    if vida <= 0:
        morrer()

func calcular_dano_critico(dano_base: int) -> int:
    return dano_base * 2

Anatomia rápida: quantidade: int é um parâmetro (o valor que entra), e o -> int declara o tipo do que sai pelo return. Quando a função não devolve nada, o retorno é -> void. Chamar é só usar o nome com os argumentos: causar_dano(25).

Funções que começam com underline, como _ready() e _process(), são as funções de ciclo de vida que a engine chama sozinha. A mais importante depois do _ready() é o _process(delta), que roda a cada frame. O delta é o tempo em segundos desde o frame anterior, e multiplicar movimento por ele garante a mesma velocidade em qualquer máquina, rodando a 30 ou a 144 FPS.

Próximo nível
Quer aprender isso na prática?

No CursoGame.Dev você sai dos tutoriais soltos e constrói jogos publicáveis, com trilha progressiva, quests práticas e feedback real.

Conhecer a plataforma
+500 alunos4.9/5Garantia 7 dias

Decisões e repetições

Todo comportamento de jogo se resume a decidir e repetir. Decidir é o if:

if vida <= 0:
    print("game over")
elif vida < 30:
    print("vida baixa!")
else:
    print("tudo certo")

Quando a decisão tem muitos casos sobre o mesmo valor, o match fica mais limpo que uma escada de elif:

match arma_atual:
    "espada":
        dano = 10
    "machado":
        dano = 15
    _:
        dano = 1  # o underline é o caso "qualquer outro"

Repetir é o for e o while:

# Percorre cada item de uma lista.
for item in inventario:
    print(item)

# Repete um número fixo de vezes (0, 1, 2, 3, 4).
for i in range(5):
    print(i)

# Repete enquanto a condição for verdadeira.
while vida > 0:
    vida -= 10

Cuidado clássico com while: se a condição nunca vira falsa, o jogo trava num loop infinito. Na prática de jogo você usa muito mais for e quase nunca while.

Seu primeiro script de verdade: movendo algo na tela

Hora de juntar tudo. Crie uma cena 2D, adicione um node Sprite2D, arraste qualquer imagem pra propriedade Texture dele (o ícone icon.svg que todo projeto Godot tem serve) e anexe este script:

extends Sprite2D

@export var velocidade: float = 300.0

func _process(delta: float) -> void:
    var direcao := Vector2.ZERO

    if Input.is_action_pressed("ui_right"):
        direcao.x += 1
    if Input.is_action_pressed("ui_left"):
        direcao.x -= 1
    if Input.is_action_pressed("ui_down"):
        direcao.y += 1
    if Input.is_action_pressed("ui_up"):
        direcao.y -= 1

    # normalized() impede que a diagonal seja mais rápida.
    position += direcao.normalized() * velocidade * delta

Rode com F5 e mexa o sprite com as setas do teclado. As ações ui_right, ui_left, ui_up e ui_down já vêm mapeadas pras setas em todo projeto Godot, então funciona sem configurar nada.

Esse script pequeno usa quase tudo do artigo: variável tipada, função de ciclo de vida, if, Vector2 e delta. E tem uma novidade: o @export. Essa anotação faz a variável aparecer no Inspector do editor, então você (ou um game designer do time) ajusta a velocidade testando o jogo, sem abrir o código. Acostume a expor todo valor de tuning assim.

Detalhe honesto: pra personagem com colisão de verdade, o node certo é o CharacterBody2D, não o Sprite2D. Mas o conceito de ler input e mover por delta é idêntico, e começar sem física deixa a lógica nua na frente de você.

Sinais: nodes conversando entre si

Antes de fechar, um conceito que você vai esbarrar já na primeira semana: sinais. Um sinal é um aviso que um node emite quando algo acontece, e outros nodes podem escutar. Botão emite pressed quando é clicado, Timer emite timeout quando o tempo acaba, Area2D emite body_entered quando algo entra nela.

Você conecta pelo editor (aba Node, ao lado do Inspector) ou por código:

func _ready() -> void:
    $Botao.pressed.connect(_ao_clicar)

func _ao_clicar() -> void:
    print("botão clicado")

O $Botao é um atalho pra pegar um node filho pelo nome. Sinais são o jeito Godot de evitar que tudo dependa de tudo, e quanto antes você adotar, mais limpo seu projeto cresce.

Os tropeços mais comuns de quem está começando

Alguns erros que todo iniciante comete e que valem conhecer antes:

  • Indentação errada. Mensagens como "Unexpected indentation" quase sempre são uma linha desalinhada ou tab misturado com espaço. Use só o editor do Godot e o problema some.
  • Esquecer o delta. Movimento sem * delta no _process fica mais rápido em PC mais rápido. Sempre multiplique.
  • Mexer em node antes do _ready(). Referência a filho com $ só funciona depois que a cena montou. Se precisar guardar a referência, use @onready var botao = $Botao.
  • Comparar com = em vez de ==. Um sinal de igual atribui, dois comparam. O Godot acusa o erro, mas a mensagem confunde no começo.

Fechando

GDScript do zero se resume a menos do que parece: var e tipos pra guardar estado, func pra organizar lógica, if e for pra decidir e repetir, e as funções de ciclo de vida (_ready, _process) como porta de entrada da engine no seu código. Com isso você já move coisas na tela, e mover coisas na tela é 80% do caminho emocional pra continuar aprendendo.

O próximo passo não é decorar mais sintaxe, é usar a pouca que você tem. Pegue o script do sprite, adicione uma variável de vida, faça ele imprimir algo ao apertar espaço, quebre o código e conserte. Linguagem de programação se aprende igual instrumento: tocando, errando e tocando de novo.