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.7 · Máquina de estados em GDScript

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

Objetivos de aprendizagem

  1. Reescrever em GDScript a máquina de estados do cão do Cajueiral (Aula 6.3).
  2. Usar enum para dar nome aos estados e match para escolher o que fazer em cada um.
  3. Concentrar a troca de estado numa função só, que também avisa por sinal.
  4. Usar @export para 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--> PERSEGUE

A 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 / Bravotexture = CALMO ou BRAVO
Personagem de caminho contornando cercasnã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)

  1. Abra cao_de_guarda.tscn e execute. Ande com as setas perto do cão: o texto no canto muda (PATRULHA, PERSEGUE, VOLTA).
  2. Selecione o nó Cao e veja no Inspetor as variáveis @export (captura abaixo). Mude Velocidade Perseguicao para 150 e teste.
  3. Na aba Sinais do Cao, veja estado_mudou ligado ao Estado.

Parte B. Desenhar e conferir (60 min)

  1. Desenhe a máquina no papel com as 5 setas.
  2. Para cada seta, ache a linha do cao.gd que a faz.

Parte C. Fazer o seu (150 min)

  1. Escolha um inimigo do seu jogo do Módulo 6 e escreva a máquina dele em GDScript, com enum, match e mudar_estado.
  2. Mostre o estado num Label usando sinal.
  3. Acrescente um quarto estado (por exemplo, DORMINDO: fica parado 3 segundos depois de voltar ao posto).

Parte D. Teste (60 min)

  1. 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, enum e as constantes.
  • ../../../recursos/imagens/godot/captura-godot-cao-inspetor.png: a cena do cão com o nó Cao selecionado.
  • ../../../recursos/imagens/godot/laboratorio-tela-cao.png: a cena rodando.

Indicação da interface

ItemNome na tela
variáveis @exportInspetor do nó, com o nome "arrumado" (velocidade_perseguicao aparece como Velocidade Perseguicao)
escolher o nó jogadorpropriedade Jogador no Inspetor (botão de escolher nó)
sinal próprioaba 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 == alvo funciona porque move_toward para 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

SintomaCausaSolução
erro ao executar: jogador é nullnão escolheu o nó no Inspetorpreencher a propriedade Jogador
o cão fica trocando de estado sem pararmesma distância para ver e desistirduas distâncias com folga
o texto da tela não mudasinal não conectado ao Labelconectar estado_mudou ao método set_text
cão para no ponto e não voltacomparou posição com número quebradousar 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, match e 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?