Pular para o conteúdo
Jogos Digitais
Nesta página
  1. Objetivos de aprendizagem
  2. Pré-requisitos
  3. Materiais
  4. Conceitos
  5. Exemplos
  6. Tutorial passo a passo
  7. Imagens
  8. Indicação da interface
  9. O código completo
  10. Explicação do código
  11. Resultado esperado
  12. Problemas comuns
  13. Exercício guiado
  14. Desafio individual
  15. Desafio avançado (opcional)
  16. Critérios de avaliação
  17. Checklist de conclusão
  18. Extensão

Módulo 8 · Aula 8.5 · Cenas reutilizáveis e o tempo

Carga horáriaDificuldadeFerramentaCompetências
8 h/a⭐⭐⭐Godot 4.7C1, C2

Objetivos de aprendizagem

  1. Criar nós pelo código a partir de uma cena (preload + instantiate + add_child).
  2. Sortear posições com randf_range.
  3. Usar call_deferred quando a mudança acontece no meio da física.
  4. Contar o tempo da partida com um nó Timer e 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 iguaisuma cena do inimigo e instantiate()
algo a cada 2 segundosTimer sem one_shot, wait_time = 2
fim da partida em 60 sTimer com one_shot e start(60)
mudar algo durante uma colisãocall_deferred ou set_deferred

Tutorial passo a passo

Parte A. Criar pelo código (120 min)

  1. No seu jogo, tire as sementes colocadas à mão.
  2. No script do jogo, const CENA_SEMENTE := preload("res://cenas/semente.tscn") e a função criar_semente() do código completo.
  3. 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)

  1. Em _on_semente_coletada, chame criar_semente() sem call_deferred. Execute, colete e olhe o painel Saída e o Depurador. Anote a mensagem.
  2. Troque por criar_semente.call_deferred(). A mensagem sumiu?

Parte C. O tempo da partida (120 min)

  1. Adicione um nó Timer chamado TempoPartida, com One Shot ligado.
  2. Conecte timeout a _on_tempo_partida_timeout e, por enquanto, faça um print("Acabou!").
  3. No _ready, tempo_partida.start(DURACAO).
  4. Em _process, calcule passado e mude a velocidade do redemoinho.
  5. Mostre o tempo no placar com ceili(tempo_partida.time_left).

Parte D. Teste rápido (30 min)

  1. Para não esperar 60 segundos a cada teste, mude DURACAO para 10 e depois volte. Anote no diário que fez isso.

Imagens

  • ../../../recursos/imagens/godot/captura-godot-script-jogo.png: o script jogo.gd no editor.
  • ../../../recursos/imagens/godot/sementes-godot-tela-jogo.png: três sementes sorteadas e o placar com o tempo.

Indicação da interface

ItemNome na tela
propriedades do TimerInspetor: Wait Time, One Shot, Autostart
mensagens de erro durante o jogopainel 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).
  • ceili arredonda para cima: com 0,3 s faltando, mostra 1, e não 0.
  • O y sorteado 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

SintomaCausaSolução
"Can't change this state while flushing queries"criou ou mudou área no meio da colisãocall_deferred
ponto contado a maisapareceu 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 pontoesqueceu o connectconectar ao criar
o tempo não andaTimer sem start e sem Autostartchamar 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?