pratica

Gerenciamento de Tempo e Temporizadores (Timers)

Aprenda sobre gerenciamento de tempo e temporizadores (timers)

30 min
Aula 5 de 5

Gerenciamento de Tempo e Temporizadores (Timers) ⏱️

Bem-vindos à aula sobre Gerenciamento de Tempo e Temporizadores! Nesta seção, vamos explorar como controlar o fluxo do tempo em seus jogos Godot, permitindo que você crie eventos com atraso, ações recorrentes e mecânicas baseadas em tempo.

O tempo é um elemento fundamental em qualquer jogo. Seja para um inimigo atirar a cada 3 segundos, uma poção de vida que recarrega após um tempo, ou um power-up que dura apenas 10 segundos, os temporizadores são ferramentas indispensáveis.

1. Introdução Clara

Em Godot, temos várias maneiras de lidar com o tempo. A mais comum e versátil é através do nó Timer e, para situações mais simples e de uso único, o SceneTreeTimer. Compreender e utilizar essas ferramentas de forma eficaz é crucial para criar experiências de jogo dinâmicas e responsivas.

Nesta aula prática, vamos mergulhar nos detalhes de como usar o nó Timer e o SceneTreeTimer com exemplos de código atualizados para o GDScript 4.x.

2. Explicação Detalhada com Exemplos

Por que precisamos de Temporizadores? 🤔

  • Atrasos: Executar uma ação após um certo período (ex: explosão após 2 segundos).
  • Eventos Recorrentes: Repetir uma ação em intervalos regulares (ex: inimigo atirando a cada 3 segundos).
  • Cooldowns: Impedir que o jogador use uma habilidade repetidamente (ex: habilidade com 5 segundos de recarga).
  • Duração de Efeitos: Fazer com que um efeito ou power-up dure por um tempo limitado.

O Nó Timer

O nó Timer é a forma mais robusta e flexível de gerenciar tempo em Godot. Ele é um nó que pode ser adicionado à sua cena e configurado através do Inspetor ou via código.

Propriedades Chave:

  • wait_time: (float) O tempo, em segundos, que o temporizador espera antes de emitir o sinal timeout.
  • one_shot: (bool) Se true, o temporizador emitirá timeout apenas uma vez e parará. Se false, ele repetirá indefinidamente.
  • autostart: (bool) Se true, o temporizador começará a contagem regressiva assim que a cena for carregada.
  • process_callback: (enum) Define como o temporizador processa o tempo (pode ser _process ou _physics_process).

Métodos Chave:

  • start(time_sec: float = -1.0): Inicia o temporizador. Se time_sec for fornecido, ele define wait_time antes de iniciar.
  • stop(): Para o temporizador.
  • is_stopped(): Retorna true se o temporizador estiver parado.

Sinal Chave:

  • timeout: Emitido quando o temporizador atinge o wait_time definido.

SceneTreeTimer (Atrasos de Uso Único) ⏱️➡️🎯

Para atrasos simples e de uso único, especialmente quando você não precisa de um nó Timer persistente na sua cena, Godot 4 oferece o SceneTreeTimer. Ele é útil para pausas rápidas ou para esperar por um evento sem a necessidade de criar e gerenciar um nó Timer completo.

Você pode usá-lo com await para pausar a execução do código até que o tempo expire, ou conectar seu sinal timeout a uma função.

3. Código de Exemplo Oficial (Adaptado da Documentação)

Vamos criar uma cena simples para demonstrar o uso do nó Timer e do SceneTreeTimer.

Exemplo 1: Usando o Nó Timer para Eventos Recorrentes

  1. Crie uma nova cena 2D (Node2D).
  2. Adicione um nó Timer como filho do Node2D e renomeie-o para MeuTimerRecorrente.
  3. No Inspetor, defina:
    • Wait Time: 1.0 (1 segundo)
    • One Shot: false (para que ele repita)
    • Autostart: true (para que ele comece automaticamente)
  4. Anexe um script ao seu Node2D principal (ou ao próprio MeuTimerRecorrente).
# Arquivo: main_scene.gd
extends Node2D
 
@onready var meu_timer_recorrente: Timer = $MeuTimerRecorrente
 
var contador: int = 0
 
func _ready() -> void:
    # Conecta o sinal 'timeout' do timer à função '_on_meu_timer_recorrente_timeout'
    meu_timer_recorrente.timeout.connect(_on_meu_timer_recorrente_timeout)
    # Se 'Autostart' fosse false, usaríamos meu_timer_recorrente.start() aqui
    print("Timer recorrente iniciado. Olhe o console a cada segundo!")
 
func _on_meu_timer_recorrente_timeout() -> void:
    contador += 1
    print("Tick! O timer recorrente disparou! Contagem: ", contador)
    if contador >= 5:
        print("Parando o timer recorrente após 5 ticks.")
        meu_timer_recorrente.stop()

Ao executar esta cena, você verá "Tick! O timer recorrente disparou!" no console a cada segundo, até atingir 5 ticks.

Exemplo 2: Usando SceneTreeTimer para um Atraso Simples

Vamos adicionar um botão à nossa cena que, ao ser clicado, exibe uma mensagem após um pequeno atraso, usando SceneTreeTimer.

  1. Na mesma cena 2D, adicione um nó Button como filho.
  2. Renomeie-o para BotaoAtraso.
  3. No Inspetor do BotaoAtraso, defina Text como "Clique para Atraso".
  4. Conecte o sinal pressed() do BotaoAtraso ao script do Node2D.
# Arquivo: main_scene.gd (continuando o script anterior)
extends Node2D
 
@onready var meu_timer_recorrente: Timer = $MeuTimerRecorrente
@onready var botao_atraso: Button = $BotaoAtraso
 
var contador: int = 0
 
func _ready() -> void:
    meu_timer_recorrente.timeout.connect(_on_meu_timer_recorrente_timeout)
    print("Timer recorrente iniciado. Olhe o console a cada segundo!")
    print("Botão de atraso pronto.")
 
func _on_meu_timer_recorrente_timeout() -> void:
    contador += 1
    print("Tick! O timer recorrente disparou! Contagem: ", contador)
    if contador >= 5:
        print("Parando o timer recorrente após 5 ticks.")
        meu_timer_recorrente.stop()
 
func _on_botao_atraso_pressed() -> void:
    print("Botão clicado! Esperando 2 segundos...")
    # Cria um timer de cena que espera 2 segundos
    await get_tree().create_timer(2.0).timeout
    print("Atraso de 2 segundos terminado! Mensagem após o clique.")

Ao clicar no botão, você verá a primeira mensagem imediatamente e, após 2 segundos, a segunda mensagem aparecerá no console. A beleza do await é que ele pausa a execução apenas desta função, não o jogo inteiro.

Exemplo 3: Cooldown de Habilidade com Timer

Vamos simular uma habilidade de jogador que tem um tempo de recarga.

  1. Adicione outro Button à sua cena, renomeie-o para BotaoHabilidade.
  2. Defina Text como "Usar Habilidade".
  3. Adicione um nó Timer como filho do Node2D, renomeie-o para TimerCooldownHabilidade.
  4. No Inspetor do TimerCooldownHabilidade, defina:
    • Wait Time: 3.0 (3 segundos de cooldown)
    • One Shot: true (o cooldown acontece apenas uma vez por uso)
    • Autostart: false
  5. Conecte o sinal pressed() do BotaoHabilidade e o sinal timeout() do TimerCooldownHabilidade ao script do Node2D.
# Arquivo: main_scene.gd (continuando o script)
extends Node2D
 
@onready var meu_timer_recorrente: Timer = $MeuTimerRecorrente
@onready var botao_atraso: Button = $BotaoAtraso
@onready var botao_habilidade: Button = $BotaoHabilidade
@onready var timer_cooldown_habilidade: Timer = $TimerCooldownHabilidade
 
var contador: int = 0
var habilidade_pronta: bool = true
 
func _ready() -> void:
    meu_timer_recorrente.timeout.connect(_on_meu_timer_recorrente_timeout)
    timer_cooldown_habilidade.timeout.connect(_on_timer_cooldown_habilidade_timeout)
    
    print("Timer recorrente iniciado. Olhe o console a cada segundo!")
    print("Botão de atraso pronto.")
    print("Habilidade pronta para uso.")
 
func _on_meu_timer_recorrente_timeout() -> void:
    contador += 1
    print("Tick! O timer recorrente disparou! Contagem: ", contador)
    if contador >= 5:
        print("Parando o timer recorrente após 5 ticks.")
        meu_timer_recorrente.stop()
 
func _on_botao_atraso_pressed() -> void:
    print("Botão clicado! Esperando 2 segundos...")
    await get_tree().create_timer(2.0).timeout
    print("Atraso de 2 segundos terminado! Mensagem após o clique.")
 
func _on_botao_habilidade_pressed() -> void:
    if habilidade_pronta:
        print("Habilidade usada! Entrando em cooldown...")
        habilidade_pronta = false
        botao_habilidade.disabled = true # Desabilita o botão durante o cooldown
        timer_cooldown_habilidade.start() # Inicia o timer de cooldown
    else:
        print("Habilidade em cooldown! Tempo restante: %.1f segundos" % timer_cooldown_habilidade.time_left)
 
func _on_timer_cooldown_habilidade_timeout() -> void:
    print("Cooldown da habilidade terminado! Habilidade pronta novamente.")
    habilidade_pronta = true
    botao_habilidade.disabled = false # Habilita o botão novamente

Neste exemplo, o botão "Usar Habilidade" só pode ser clicado novamente após o TimerCooldownHabilidade ter terminado sua contagem regressiva de 3 segundos. Enquanto está em cooldown, o botão fica desabilitado e uma mensagem informa o tempo restante.

4. Integração com Múltiplas Tecnologias (N/A)

Este módulo foca exclusivamente no GDScript e nos recursos nativos do Godot Engine para gerenciamento de tempo. Não há integração com tecnologias externas neste tópico específico, pois o Godot oferece todas as ferramentas necessárias para isso de forma interna e otimizada.

5. Exercícios/Desafios 🚀

Agora é a sua vez de praticar! Crie uma nova cena e tente implementar os seguintes desafios:

Desafio 1: Inimigo Atirador Periódico 👾🔫

Crie um inimigo simples (pode ser um CharacterBody2D ou Node2D com uma Sprite2D) que atira projéteis a cada 2.5 segundos.

  • Crie uma nova cena para o inimigo.
  • Adicione um nó Timer ao inimigo.
  • Configure o Timer para disparar a cada 2.5 segundos (wait_time = 2.5, one_shot = false, autostart = true).
  • Conecte o sinal timeout do Timer a uma função no script do inimigo.
  • Dentro dessa função, imprima uma mensagem como "Inimigo atirou!" ou instancie um projétil (se você já tiver um).

Desafio 2: Ciclo Dia/Noite Simples ☀️🌙

Implemente um ciclo dia/noite básico que muda a cor de fundo da tela (ou um ColorRect) a cada 5 segundos, alternando entre uma cor clara (dia) e uma cor escura (noite).

  • Crie uma nova cena principal.
  • Adicione um nó ColorRect como filho do nó raiz para representar o céu. Certifique-se de que ele cubra a tela inteira.
  • Adicione um nó Timer à cena.
  • Configure o Timer para disparar a cada 5 segundos (wait_time = 5.0, one_shot = false, autostart = true).
  • No script da cena principal, mantenha uma variável booleana e_dia (inicialmente true).
  • Conecte o sinal timeout do Timer a uma função.
  • Dentro da função:
    • Inverta o valor de e_dia.
    • Se e_dia for true, mude a cor do ColorRect para uma cor clara (ex: Color.SKY_BLUE).
    • Se e_dia for false, mude a cor do ColorRect para uma cor escura (ex: Color.DARK_BLUE).

Desafio 3: Power-up de Duração Limitada 🍄✨

Crie um power-up que, ao ser "coletado" (simulado por um clique de botão), ativa um efeito por 7 segundos e depois o desativa automaticamente.

  • Crie uma nova cena principal.
  • Adicione um Button com o texto "Coletar Power-up".
  • Adicione um Label para exibir o status do power-up (ex: "Power-up: Inativo" ou "Power-up: Ativo!").
  • Adicione um nó Timer à cena, renomeie-o para TimerPowerUp.
  • Configure o TimerPowerUp para ter wait_time = 7.0, one_shot = true, autostart = false.
  • No script da cena principal:
    • Crie uma variável booleana power_up_ativo (inicialmente false).
    • Conecte o sinal pressed() do botão a uma função.
    • Conecte o sinal timeout() do TimerPowerUp a outra função.
  • Na função _on_button_pressed():
    • Se power_up_ativo for false:
      • Defina power_up_ativo = true.
      • Atualize o texto do Label para "Power-up: Ativo!".
      • Inicie o TimerPowerUp.
      • Desabilite o botão para evitar múltiplos cliques enquanto o power-up está ativo.
    • Se power_up_ativo for true, imprima uma mensagem como "Power-up já está ativo!".
  • Na função _on_timer_power_up_timeout():
    • Defina power_up_ativo = false.
    • Atualize o texto do Label para "Power-up: Inativo".
    • Habilite o botão novamente.

6. Resumo e Próximos Passos

Nesta aula, você aprendeu sobre a importância do gerenciamento de tempo em jogos e como utilizar as ferramentas de temporização do Godot:

  • Timer: Ideal para eventos recorrentes, cooldowns e atrasos controlados, com propriedades configuráveis no Inspetor.
  • SceneTreeTimer: Perfeito para atrasos de uso único e pausas assíncronas no código usando await.

Dominar o uso de temporizadores abre um leque enorme de possibilidades para a criação de mecânicas de jogo complexas e dinâmicas.

Próximos Passos:

  • Experimente combinar temporizadores com animações e efeitos visuais.
  • Explore como os temporizadores podem ser pausados e retomados em um menu de pausa do jogo.
  • Pense em como você pode usar temporizadores para gerenciar a vida útil de projéteis ou partículas.

Continue praticando e aplicando esses conceitos em seus próprios projetos! 🎮✨

© 2025 Escola All Dev. Todos os direitos reservados.

Gerenciamento de Tempo e Temporizadores (Timers) - Fundamentos do Godot: Desenvolvimento de games para iniciantes | escola.all.dev.br