Módulo 8 · Aula 8.7 · Máquina de estados em GDScript
| Carga horária | Dificuldade | Ferramenta | Competências |
|---|---|---|---|
| 8 h/a | ⭐⭐⭐ | Godot 4.7 | C1, C2 |
Objetivos de aprendizagem
- Reescrever em GDScript a máquina de estados do cão do Cajueiral (Aula 6.3).
- Usar
enumpara dar nome aos estados ematchpara escolher o que fazer em cada um. - Concentrar a troca de estado numa função só, que também avisa por sinal.
- Usar
@exportpara ajustar números no Inspetor sem mexer no código.
Pré-requisitos
Aula 6.3 (máquina de estados no GDevelop). Aulas 8.3 e 8.4.
Materiais
Godot 4.7; laboratório, cena cao_de_guarda.tscn e script cao.gd.
Conceitos
Os três estados de novo.
PATRULHA --jogador a menos de 150 px--> PERSEGUE --jogador a mais de 260 px--> VOLTA
VOLTA --chegou ao posto--> PATRULHA VOLTA --jogador a menos de 150 px--> PERSEGUEA folga entre 150 e 260 evita o cão trocar de estado sem parar na fronteira, igual ao Cajueiral.
enum. Lista de nomes que viram números: enum Estado { PATRULHA, PERSEGUE, VOLTA }. Escrever Estado.PERSEGUE é mais claro que 1 e o editor avisa se o nome estiver errado. No Cajueiral o estado era um texto ("persegue"); um erro de digitação ali passava sem aviso.
match. Escolhe um bloco conforme o valor, como vários if seguidos, mais organizado:
match estado:
Estado.PATRULHA:
...
Estado.PERSEGUE:
...Uma função para trocar. Toda troca passa por mudar_estado(novo), que muda a variável, troca o desenho (calmo ou bravo) e emite o sinal estado_mudou. No laboratório, esse sinal está ligado direto ao set_text do Label Estado: o texto da tela muda sozinho, sem uma linha de código no Label.
@export. A variável aparece no Inspetor. ponto_a, ponto_b, as velocidades e até o nó jogador são escolhidos no editor. Cada cão da fase pode ter os seus.
Exemplos
| Cajueiral (GDevelop, Módulo 6) | Laboratório (Godot) |
|---|---|
variável de objeto Estado (texto) | var estado := Estado.PATRULHA |
| eventos com condição "Estado = persegue" | match estado: |
| pontos da patrulha nas variáveis da instância | @export var ponto_a, ponto_b |
| animação Calmo / Bravo | texture = CALMO ou BRAVO |
| Personagem de caminho contornando cercas | não tem: aqui o cão anda em linha reta (veja o Desafio avançado) |
Tutorial passo a passo
Parte A. Ler e testar (90 min)
- Abra
cao_de_guarda.tscne execute. Ande com as setas perto do cão: o texto no canto muda (PATRULHA,PERSEGUE,VOLTA). - Selecione o nó
Caoe veja no Inspetor as variáveis@export(captura abaixo). MudeVelocidade Perseguicaopara 150 e teste. - Na aba Sinais do
Cao, vejaestado_mudouligado aoEstado.
Parte B. Desenhar e conferir (60 min)
- Desenhe a máquina no papel com as 5 setas.
- Para cada seta, ache a linha do
cao.gdque a faz.
Parte C. Fazer o seu (150 min)
- Escolha um inimigo do seu jogo do Módulo 6 e escreva a máquina dele em GDScript, com
enum,matchemudar_estado. - Mostre o estado num
Labelusando sinal. - Acrescente um quarto estado (por exemplo,
DORMINDO: fica parado 3 segundos depois de voltar ao posto).
Parte D. Teste (60 min)
- Monte uma tabela: situação, estado esperado, estado que apareceu. Teste as 5 setas da máquina.
Imagens
../../../recursos/imagens/godot/captura-godot-script-cao.png
: o script com signal,enume as constantes.../../../recursos/imagens/godot/captura-godot-cao-inspetor.png
: a cena do cão com o nó Caoselecionado.../../../recursos/imagens/godot/laboratorio-tela-cao.png
: a cena rodando.
Indicação da interface
| Item | Nome na tela |
|---|---|
variáveis @export | Inspetor do nó, com o nome "arrumado" (velocidade_perseguicao aparece como Velocidade Perseguicao) |
escolher o nó jogador | propriedade Jogador no Inspetor (botão de escolher nó) |
| sinal próprio | aba Sinais, no topo da lista, com o nome do script |
O código completo
exemplos/laboratorio/scripts/cao.gd:
extends Sprite2D
signal estado_mudou(nome_do_estado: String)
enum Estado { PATRULHA, PERSEGUE, VOLTA }
const DISTANCIA_VE := 150.0 # vê o jogador a menos disto
const DISTANCIA_DESISTE := 260.0 # desiste a mais disto (folga para não ficar trocando)
const CALMO := preload("res://imagens/cao_calmo1.png")
const BRAVO := preload("res://imagens/cao_bravo1.png")
@export var jogador: Node2D
@export var ponto_a := Vector2(200, 300)
@export var ponto_b := Vector2(600, 300)
@export var velocidade_patrulha := 60.0
@export var velocidade_perseguicao := 110.0
var estado := Estado.PATRULHA
var indo_para_b := true
func _process(delta: float) -> void:
var distancia := position.distance_to(jogador.position)
match estado:
Estado.PATRULHA:
var alvo := ponto_b if indo_para_b else ponto_a
andar_ate(alvo, velocidade_patrulha, delta)
if position == alvo:
indo_para_b = not indo_para_b
if distancia < DISTANCIA_VE:
mudar_estado(Estado.PERSEGUE)
Estado.PERSEGUE:
andar_ate(jogador.position, velocidade_perseguicao, delta)
if distancia > DISTANCIA_DESISTE:
mudar_estado(Estado.VOLTA)
Estado.VOLTA:
andar_ate(ponto_a, velocidade_patrulha, delta)
if distancia < DISTANCIA_VE:
mudar_estado(Estado.PERSEGUE)
elif position == ponto_a:
indo_para_b = true
mudar_estado(Estado.PATRULHA)
func mudar_estado(novo: Estado) -> void:
estado = novo
texture = BRAVO if novo == Estado.PERSEGUE else CALMO
estado_mudou.emit(Estado.keys()[novo])
func andar_ate(alvo: Vector2, velocidade: float, delta: float) -> void:
if alvo.x != position.x:
flip_h = alvo.x < position.x
position = position.move_toward(alvo, velocidade * delta)Explicação do código
Estado.keys()[novo]transforma o número do estado no nome ("PERSEGUE"), para mostrar na tela.position == alvofunciona porquemove_towardpara exatamente no alvo, sem passar.- O teste automático do laboratório confere as 5 setas, o sinal no
Label, a troca de desenho e a velocidade de perseguição.
Resultado esperado
Inimigo com enum, match e mudar_estado, estado visível na tela por sinal, e tabela de teste preenchida.
Problemas comuns
| Sintoma | Causa | Solução |
|---|---|---|
erro ao executar: jogador é null | não escolheu o nó no Inspetor | preencher a propriedade Jogador |
| o cão fica trocando de estado sem parar | mesma distância para ver e desistir | duas distâncias com folga |
| o texto da tela não muda | sinal não conectado ao Label | conectar estado_mudou ao método set_text |
| cão para no ponto e não volta | comparou posição com número quebrado | usar move_toward, que chega exatamente |
Exercício guiado
O jogador está a 200 px do cão. Em qual estado o cão fica se estava em PATRULHA? E se estava em PERSEGUE? (Resposta: continua em PATRULHA, porque 200 não é menor que 150; continua em PERSEGUE, porque 200 não é maior que 260.)
Desafio individual
Faça o cão "latir" (print ou som) só uma vez, no momento em que entra em PERSEGUE. Dica: o lugar certo é mudar_estado.
Desafio avançado (opcional)
Pesquise na documentação oficial o nó NavigationAgent2D, o equivalente ao Personagem de caminho do GDevelop, e anote como ele seria usado para o cão contornar obstáculos. (Não foi testado nesta versão do curso.)
Critérios de avaliação
- Máquina desenhada igual ao código.
enum,matche uma função de troca.- Tabela de teste com as setas.
Checklist de conclusão
Extensão
Desenhe a máquina de estados de um semáforo de pedestre (verde, piscando, vermelho). Quais são as setas e o que as dispara?