O que é um nó
Um nó é uma peça com uma função só. O Sprite2D mostra uma imagem. O CollisionShape2D dá um corpo para bater nas coisas. O Camera2D decide o que aparece na tela. Sozinhos eles fazem pouco; juntos viram um personagem.
Na demonstração lá em cima, tire o CollisionShape2D e repare no aviso. O Godot mostra esse mesmo aviso (o triângulo amarelo) quando um corpo está sem forma de colisão.
“Pensa no Lego. Uma pecinha sozinha não é nada. Mas uma roda, mais um volante, mais um banco, vira um carro. No Godot cada pecinha se chama nó, e o carro montado se chama cena.”
- Olha que legal: na demo, adicione só o Sprite2D. Dá para ver o robô, mas ele não “existe” para a física. Ele atravessaria uma parede.
- Pergunte: “Quais nós o seu personagem tem hoje? Abre o projeto e me mostra.”
Pai e filho: a árvore de cena
Os nós ficam numa árvore. O nó de cima é o pai e os de dentro são os filhos. A regra de ouro: o filho vai aonde o pai vai. A posição do filho é contada a partir do pai. Isso se chama posição local; a posição de verdade na tela é a global.
“A espada é filha do Jogador. Quando o Jogador anda, ninguém precisa mandar a espada andar: ela vai junto, sozinha. É como a sua mochila: você não precisa mandar a mochila ir pra escola, ela vai porque está presa em você.”
- Olha que legal: mexa só no slider do Jogador. A espada segue. Depois mexa só na Espada: ela muda de lado, mas continua presa ao Jogador.
- Pergunte: “Se eu quero que a câmera siga o personagem, onde eu coloco o nó Camera2D?” (Resposta: como filho do personagem.)
Catálogo de nós que valem a pena conhecer
O Godot tem centenas de nós, mas uns dez resolvem quase tudo num jogo 2D. Repare na cor do ícone no editor: ela diz a família do nó.
“Você não precisa decorar todos. Programador de verdade pesquisa. O segredo é saber que eles existem. Quando pensar ‘queria que algo acontecesse a cada 3 segundos’, você lembra: tem o Timer!”
- Desafio rápido: peça para o aluno escolher um nó do catálogo que ainda não usou e colocar no jogo dele hoje.
GDScript: o “Python” do Godot
GDScript foi feita para parecer Python. Se você aprender um, já sabe metade do outro. As duas usam indentação (o recuo com Tab) para saber o que fica dentro de quê. A diferença maior: em Python a função começa com def, e em GDScript com func.
# uma variável
vida = 3
# uma função
def levar_dano(quanto):
global vida
vida = vida - quanto
if vida <= 0:
print("Game Over")
levar_dano(1)extends CharacterBody2D
# uma variável
var vida = 3
# uma função
func levar_dano(quanto):
vida = vida - quanto
if vida <= 0:
print("Game Over")
queue_free() # some da tela“Olha como é quase igual! Quem aprende GDScript está aprendendo Python de brinde, e Python é uma das linguagens mais usadas do mundo: inteligência artificial, sites, robótica.”
- Olha que legal: a primeira linha,
extends CharacterBody2D, diz que esse script “é” um CharacterBody2D. Por isso ele já sabe usarvelocityemove_and_slide()sem a gente programar isso. - Pergunte: “O que acontece se eu tirar o Tab da linha do print?” (O Godot acusa erro, porque não sabe mais que o print está dentro do if.)
Variáveis e tipos
Variável é uma caixinha com nome que guarda um valor. O tipo diz o que cabe na caixinha: número inteiro (int), número com vírgula (float), texto (String), verdadeiro ou falso (bool) e posição x,y (Vector2). Mexa nos controles e veja o código e o robô mudarem juntos.
“O jogo inteiro é feito de caixinhas. A vida do personagem, os pontos, a fase em que você está, se a porta está aberta ou fechada: tudo é variável.”
- Olha que legal: coloque a velocidade em 0. O robô para, mas o código continua rodando. Ele só está andando “0 pixels por segundo”.
- Pergunte: “Que tipo de caixinha você usaria para guardar se o jogador pegou a chave?” (bool)
- Dica: escrever o tipo (
var vida: int = 3) é opcional, mas ajuda o Godot a avisar erros mais cedo.
As funções que o Godot chama sozinho
Algumas funções têm nome especial e começam com _. Você não chama essas funções: o Godot chama por você, na hora certa. _ready() roda uma vez quando o nó entra na cena. _process(delta) roda a cada quadro desenhado. _physics_process(delta) roda 60 vezes por segundo, certinho, e é onde fica o movimento. _input(event) roda quando você aperta uma tecla ou clica.
Aperte “Rodar cena” (é o F5 do Godot).
func _ready():
print("Nasci!") # roda 1 vez
func _physics_process(delta):
# roda 60 vezes por segundo
position.x += velocidade * delta
func _input(event):
if event.is_action_pressed("ui_accept"):
print("Apertou Espaço ou Enter!")
“O _physics_process é o coração do jogo batendo: 60 batidas por segundo. Cada batida, o personagem anda um pouquinho. Como é muito rápido, o olho vê movimento, igual desenho animado.”
- Olha que legal: rode por 10 segundos e veja o contador de física passar de 600. Isso é 60 × 10.
- O que é delta: o tempo entre uma batida e outra. Multiplicar a velocidade por delta faz o jogo andar igual em computador rápido e em computador lento.
- Pergunte: “Onde você colocaria um código que toca a música do jogo uma vez só, no começo?” (no _ready)
if, elif, else: o jogo tomando decisões
O if pergunta algo que é verdadeiro ou falso. Se for verdade, roda o que está dentro. O elif (“senão, se”) faz outra pergunta, e o else (“senão”) pega todo o resto. Só um caminho roda de cada vez. Arraste a vida e veja qual linha acende.
“O if é o cérebro do jogo. O inimigo te viu? A porta está trancada? Você pegou todas as moedas? Toda decisão do jogo é um if.”
- Olha que legal: coloque a vida em exatamente 30. Cai no else, porque 30 não é menor que 30. Os sinais
<e<=fazem diferença! - Comparações:
==igual,!=diferente,<menor,>maior. Um=só guarda valor; dois==comparam.
for: repetir sem copiar e colar
O for repete um bloco de código várias vezes. range(5) gera os números 0, 1, 2, 3, 4, e a variável i recebe um de cada vez. Repare: começa no zero.
“Imagina colocar 100 moedas na fase arrastando uma por uma. Cansativo, né? Com 2 linhas de for o computador faz isso pra gente. Programador é preguiçoso do jeito certo: faz o computador trabalhar.”
- Olha que legal: coloque 12 e rode. Cada moeda fica num lugar diferente porque a posição usa o
i:i * 50.
Funções: dar nome a uma ação
Uma função é um pedaço de código com nome, que você chama quando quiser. Ela pode receber valores (os parâmetros, entre parênteses) e pode devolver um resultado com return.
func pular(forca: float) -> void: if is_on_floor(): velocity.y = -forca # para cima é negativo! func calcular_dano(base: int, critico: bool) -> int: if critico: return base * 2 return base # usando: pular(300) var dano = calcular_dano(10, true) # dano vale 20
“Função é como um botão de controle remoto. Você não precisa saber como a TV funciona por dentro, só aperta ‘aumentar volume’. Aqui o botão se chama pular, e o número entre parênteses diz a força.”
- Olha que legal: no Godot, o eixo Y é para baixo. Por isso pular é velocidade negativa. Isso confunde todo mundo no começo!
- Pergunte: “Que ações do seu jogo poderiam virar funções?” (atacar, morrer, abrir porta, pegar item)
Sinais: os nós conversando
Um sinal é um aviso que um nó dá quando algo acontece com ele. A Area2D avisa “alguém entrou em mim” (body_entered). O Button avisa “fui apertado” (pressed). O Timer avisa “acabou o tempo” (timeout). Outros nós escutam o aviso e reagem. Arraste o robô até as moedas (ou clique na área e use as setas).
Nenhum sinal ainda. Encoste o robô numa moeda.
extends Area2D # moeda.gd signal coletada # um sinal criado por nós func _ready(): body_entered.connect(_on_body_entered) func _on_body_entered(body): if body.name == "Jogador": coletada.emit() # avisa quem estiver escutando queue_free()
“Sinal é como a campainha da sua casa. A campainha não sabe quem vai atender. Ela só toca. Quem estiver ouvindo vai até a porta. A moeda faz a mesma coisa: só avisa ‘me pegaram!’, e o placar, o som e o que mais quiser escutar reagem.”
- Olha que legal: no editor, selecione qualquer nó e abra a aba Nó (ao lado do Inspetor). Ali aparece a lista de todos os sinais que ele pode dar. Dá para conectar com dois cliques, sem código.
- Por que é importante: com sinais, a moeda não precisa conhecer o placar. Cada nó cuida da sua vida, e o jogo fica organizado mesmo quando cresce.
- Pergunte: “Que sinal você usaria para o inimigo perceber que o jogador chegou perto?” (body_entered de uma Area2D em volta do inimigo)
@export: mexer no código pelo Inspetor
Colocando @export antes de uma variável, ela aparece no Inspetor. Aí dá para ter um script só e vários inimigos diferentes: cada cópia com sua vida, velocidade e cor, sem mexer no código.
“Os dois inimigos usam o mesmíssimo script. A diferença está só nos valores do Inspetor. É assim que jogos grandes fazem dezenas de inimigos sem escrever dezenas de códigos.”
- Olha que legal: com
@export, até quem não programa (um designer de fases) consegue ajustar o jogo. Peça ao aluno para exportar a velocidade do personagem dele e testar valores com o jogo rodando.
Cenas como moldes: instanciar
Uma cena salva (inimigo.tscn) é um molde. Com preload o jogo carrega o molde, e com instantiate() cria uma cópia nova enquanto o jogo roda. Junto com um Timer, dá para fazer inimigos nascerem sem parar. Ligue o Timer e veja a árvore de cena crescer e diminuir.
Timer desligado.
extends Node2D # principal.gd
const INIMIGO = preload("res://cenas/inimigo.tscn")
func _on_timer_timeout():
var novo = INIMIGO.instantiate()
novo.position = Vector2(randf_range(0, 400), 0)
add_child(novo)
# e no inimigo.gd, para sumir ao sair da tela:
func _physics_process(delta):
position.y += 120 * delta
if position.y > 700:
queue_free()
“A cena é como a forminha de biscoito. Você faz a forminha uma vez e tira quantos biscoitos quiser. Tiros, inimigos, moedas, explosões: tudo nasce assim.”
- Olha que legal: repare que cada inimigo que sai da tela é apagado com
queue_free(). Se não apagar, eles continuam existindo invisíveis e o jogo fica lento. - Dica de editor: com o jogo rodando, a aba Remoto no painel Cena mostra a árvore ao vivo, igual a esta demonstração.
Roteiro de 60 minutos
A ideia é alternar: mostrar a demonstração, fazer a pergunta e deixar o aluno aplicar no jogo dele. Ele já sabe fazer o personagem andar, então use o projeto dele como laboratório.
| Tempo | O que fazer | No jogo do aluno |
|---|---|---|
| 0–5 min | Abrir esta página. Montar o Jogador na demonstração do topo. | Ele mostra a árvore de cena do personagem dele e explica cada nó. |
| 5–15 min | Nós, pai e filho, catálogo. | Colocar uma Camera2D como filha do personagem e ver a câmera seguir. |
| 15–25 min | GDScript e Python, variáveis e tipos. | Ler o script de movimento dele e apontar cada variável e o tipo dela. |
| 25–35 min | _ready e _physics_process, if, funções. | Colocar print("Nasci!") no _ready e ver aparecer no painel Saída. |
| 35–50 min | Sinais (com calma, é o mais importante). | Criar uma moeda com Area2D que some ao ser tocada, usando body_entered. |
| 50–57 min | @export e instanciar. | Colocar @export na velocidade e ajustar pelo Inspetor. |
| 57–60 min | Revisão com as perguntas abaixo. | Anotar uma ideia para a próxima aula. |
Perguntas de revisão
- Se o pai anda, o que acontece com o filho? (vai junto)
- Qual função roda uma vez só, quando o nó nasce? (_ready)
- Qual a diferença entre
=e==? (guardar e comparar) - O que um sinal faz? (avisa que algo aconteceu, e quem escuta reage)
- Para que serve o
@export? (mudar o valor pelo Inspetor)
Se sobrar tempo ou para casa
- Fazer um placar com
Labelque sobe quando a moeda emite o sinalcoletada. - Usar um
Timerpara fazer moedas nascerem a cada 2 segundos. - Criar uma função
levar_dano(quanto)e umifque reinicia a fase quando a vida chega a 0, comget_tree().reload_current_scene().
Você não precisa saber tudo. Quando o aluno perguntar algo que você não sabe, diga: “Boa pergunta, vamos descobrir juntos”, e pesquise na documentação do Godot (docs.godotengine.org) ou pergunte para mim. Ensinar o aluno a pesquisar é uma das lições mais valiosas da programação.