Módulo 8 · Aula 8.5 · Cenas reutilizáveis e o tempo
| Carga horária | Dificuldade | Ferramenta | Competências |
|---|---|---|---|
| 8 h/a | ⭐⭐⭐ | Godot 4.7 | C1, C2 |
Objetivos de aprendizagem
- Criar nós pelo código a partir de uma cena (
preload+instantiate+add_child). - Sortear posições com
randf_range. - Usar
call_deferredquando a mudança acontece no meio da física. - Contar o tempo da partida com um nó
Timere acelerar o inimigo com o tempo.
Pré-requisitos
Aula 8.4.
Materiais
Godot 4.7; Sementes em Godot (jogo.gd).
Conceitos
Cena como molde. semente.tscn é um molde. preload("res://cenas/semente.tscn") carrega o molde quando o script abre; instantiate() faz uma cópia nova; add_child() coloca a cópia na cena. É o "criar clone" do Scratch (Aula 1.9) e o "Criar um objeto" do GDevelop (Aula 3.6).
Sorteio. randf_range(40, 760) sorteia um número com vírgula entre 40 e 760. O Godot embaralha o sorteio sozinho a cada execução.
call_deferred: deixe para o fim do quadro. A semente avisa coletada no meio do cálculo das colisões. Se o jogo cria outra área nessa hora, o Godot reclama. Conferido no Godot 4.7.2, numa cópia do Sementes sem o call_deferred:
ERROR: Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead.E não foi só a mensagem: o jogo passou a contar pontos a mais (2 em vez de 1), e três verificações do teste automático falharam. Com criar_semente.call_deferred(), a criação fica para o fim do quadro e tudo volta ao normal (35 de 35).
Timer. Nó que conta tempo e dá o sinal timeout. Com one_shot ligado, conta uma vez só. start(60) começa a contar 60 segundos; time_left diz quanto falta.
Acelerar com o tempo. O redemoinho começa a 60 px/s e ganha 1,5 px/s por segundo: 60 + 1,5 × segundos passados. Aos 30 s, 105 px/s; no fim, 150 px/s. O teste confere a fórmula.
Exemplos
| Precisa de... | Use |
|---|---|
| vários inimigos iguais | uma cena do inimigo e instantiate() |
| algo a cada 2 segundos | Timer sem one_shot, wait_time = 2 |
| fim da partida em 60 s | Timer com one_shot e start(60) |
| mudar algo durante uma colisão | call_deferred ou set_deferred |
Tutorial passo a passo
Parte A. Criar pelo código (120 min)
- No seu jogo, tire as sementes colocadas à mão.
- No script do jogo,
const CENA_SEMENTE := preload("res://cenas/semente.tscn")e a funçãocriar_semente()do código completo. - No
_ready,for i in 3: criar_semente(). Execute várias vezes: as sementes mudam de lugar?
Parte B. Sempre 3 na tela (90 min)
- Em
_on_semente_coletada, chamecriar_semente()semcall_deferred. Execute, colete e olhe o painel Saída e o Depurador. Anote a mensagem. - Troque por
criar_semente.call_deferred(). A mensagem sumiu?
Parte C. O tempo da partida (120 min)
- Adicione um nó
TimerchamadoTempoPartida, comOne Shotligado. - Conecte
timeouta_on_tempo_partida_timeoute, por enquanto, faça umprint("Acabou!"). - No
_ready,tempo_partida.start(DURACAO). - Em
_process, calculepassadoe mude a velocidade do redemoinho. - Mostre o tempo no placar com
ceili(tempo_partida.time_left).
Parte D. Teste rápido (30 min)
- Para não esperar 60 segundos a cada teste, mude
DURACAOpara 10 e depois volte. Anote no diário que fez isso.
Imagens
../../../recursos/imagens/godot/captura-godot-script-jogo.png
: o script jogo.gdno editor.../../../recursos/imagens/godot/sementes-godot-tela-jogo.png
: três sementes sorteadas e o placar com o tempo.
Indicação da interface
| Item | Nome na tela |
|---|---|
| propriedades do Timer | Inspetor: Wait Time, One Shot, Autostart |
| mensagens de erro durante o jogo | painel Depurador (aba Erros) e Saída |
O código completo
Trecho de scripts/jogo.gd:
const CENA_SEMENTE := preload("res://cenas/semente.tscn")
const DURACAO := 60.0
const VELOCIDADE_INICIAL := 60.0
const ACELERACAO := 1.5 # px/s a mais a cada segundo
func _ready() -> void:
Global.pontos = 0
redemoinho.jogador = jogador
for i in 3:
criar_semente()
tempo_partida.start(DURACAO)
func _process(_delta: float) -> void:
var passado := DURACAO - tempo_partida.time_left
redemoinho.velocidade = VELOCIDADE_INICIAL + ACELERACAO * passado
placar.text = "Sementes: %d Vidas: %d Tempo: %d" % [Global.pontos, vidas, ceili(tempo_partida.time_left)]
func criar_semente() -> void:
var semente := CENA_SEMENTE.instantiate()
semente.position = Vector2(randf_range(40, 760), randf_range(80, 560))
semente.coletada.connect(_on_semente_coletada)
add_child(semente)
func _on_semente_coletada() -> void:
Global.pontos += 1
som_coleta.play()
# A semente avisa no meio do cálculo de colisões; criar outra área agora dá erro.
# call_deferred deixa para o fim do quadro.
criar_semente.call_deferred()Explicação do código
semente.coletada.connect(...): a semente nova foi criada pelo código, então a conexão também é pelo código."%d" % [valor]monta texto com números (%dé número inteiro).ceiliarredonda para cima: com 0,3 s faltando, mostra 1, e não 0.- O
ysorteado começa em 80 para a semente não nascer embaixo do placar.
Resultado esperado
Sempre 3 sementes em lugares sorteados, partida de 60 segundos, redemoinho cada vez mais rápido e nenhuma mensagem de erro.
Problemas comuns
| Sintoma | Causa | Solução |
|---|---|---|
| "Can't change this state while flushing queries" | criou ou mudou área no meio da colisão | call_deferred |
| ponto contado a mais | apareceu junto com a mensagem acima, no teste sem call_deferred (o motivo exato não foi investigado) | call_deferred resolveu |
| semente nova não soma ponto | esqueceu o connect | conectar ao criar |
| o tempo não anda | Timer sem start e sem Autostart | chamar start() |
Exercício guiado
Aos 40 segundos de partida, qual a velocidade do redemoinho? (Resposta: 60 + 1,5 × 40 = 120 px/s.)
Desafio individual
Use um segundo Timer (sem one_shot, 10 segundos) para criar uma semente dourada (Aula 8.4) de vez em quando.
Desafio avançado (opcional)
Impeça a semente de nascer perto demais do redemoinho: sorteie de novo enquanto a distância for menor que 100.
Critérios de avaliação
- Cria nós pelo código e conecta seus sinais.
- Explica com as próprias palavras por que existe o
call_deferred. - Timer da partida e aceleração funcionando.
Checklist de conclusão
Extensão
Matemática: monte uma tabela tempo × velocidade (0, 10, 20... 60 s) e um gráfico. Que forma tem?