Módulo 9 · Aula 9.5 · Labirinto feito pelo código
| Carga horária | Dificuldade | Ferramenta | Competências |
|---|---|---|---|
| 10 h/a | ⭐⭐⭐ | Godot 4.7 | C1, C2, C3 |
Objetivos de aprendizagem
- Desenhar um labirinto como uma lista de textos (mapa de letras).
- Transformar linha e coluna do mapa em posição 3D.
- Criar paredes pelo código com
StaticBody3D,MeshInstance3DeCollisionShape3D. - Reaproveitar a mesma malha e a mesma forma de colisão em todas as paredes.
- Conferir no papel se o labirinto tem saída.
Pré-requisitos
Aulas 9.1 a 9.4; Aula 8.5 (criar nós pelo código); Módulo 1 (repetição dentro de repetição).
Materiais
Godot 4.7; chave-da-porteira (scripts/labirinto.gd, cenas/labirinto.tscn); papel quadriculado.
Conceitos
Mapa de letras. Cada texto é uma linha do labirinto; cada letra, um quadrado:
"###########",
"#J..#.....#",
"#.#.#.###.#",
"#.#...#C#.#",
"#.#####.#.#",
"#...#...#.#",
"###.#.###.#",
"#...#.#...#",
"#.###.#P###",
"#.....#S..#",
"###########",Legenda: # parede, . chão, J jogador, C chave, P porteira, S saída. Para mudar o labirinto, basta mudar as letras.
Do mapa para o 3D. A coluna vira X e a linha vira Z; o Y é a altura. Com quadrados de 3 m (TAMANHO), a letra da linha 1, coluna 1 fica em (3, 0, 3).
Por que montar pelo código? Arrastar 72 paredes uma a uma é demorado e qualquer mudança dá trabalho. Pelo código, a turma pode trocar de fase só trocando o texto. A desvantagem: no editor, a cena aparece sem paredes (veja a captura). Elas só existem quando o jogo roda.
Uma malha para todas. O script cria uma BoxMesh e uma BoxShape3D e entrega as duas para todas as paredes. São 72 paredes e uma única malha na memória. O teste automático confere que as paredes usam a mesma malha.
Tem saída? Antes de programar, confira no papel: do J dá para chegar no C sem passar pela P? E no S, só passando pela P? O teste automático faz essa conferência com uma "busca em largura": pinta o vizinho, depois o vizinho do vizinho, até não ter mais para onde ir.
Exemplos
| Letra | Linha | Coluna | Posição 3D (TAMANHO = 3) |
|---|---|---|---|
J | 1 | 1 | (3, 0, 3) |
C | 3 | 7 | (21, 0, 9) (a chave sobe 1 m: (21, 1, 9)) |
P | 8 | 7 | (21, 0, 24) |
S | 9 | 7 | (21, 0, 27) |
Tutorial passo a passo
Parte A. No papel (80 min)
- Copie o mapa no papel quadriculado e pinte as paredes.
- Com o dedo, ache o caminho do
Jaté oC, e doCaté oS. Passou pelaP? - Desenhe o seu próprio labirinto de 11 × 11, com as mesmas letras. Troque com a dupla: ela consegue chegar à saída? A chave fica antes da porteira?
Parte B. Ler o script (100 min)
- Abra
scripts/labirinto.gd. AcheMAPA,TAMANHO,ALTURAe a funçãomontar_labirinto. - Com a dupla, explique as duas repetições (
for linhaefor coluna) e omatch letra.
Parte C. O seu labirinto no jogo (180 min)
- Faça uma cópia do projeto
chave-da-porteira(pasta inteira, sem a pasta.godot). - Troque o
MAPApelo seu labirinto do passo 3 e execute. - Mude
TAMANHOpara 2 e depois para 4. O que acontece com os corredores e com a câmera? - Mude
ALTURApara 1 (muro baixo) e para 4 (paredão). Qual é mais divertido?
Parte D. Testar (40 min)
- Rode o teste automático (
testes/godot/testar_porteira.gd) na sua cópia. As duas primeiras verificações dizem se o seu mapa tem chave alcançável e saída só pela porteira. As outras foram escritas para o mapa original (elas põem o jogador em lugares fixos) e podem falhar com outro mapa: isso não quer dizer que o seu está errado.
Imagens
../../../recursos/imagens/godot/captura-godot3d-editor-labirinto.png
: a cena do labirinto no editor, sem paredes (elas são criadas pelo código).../../../recursos/imagens/godot/captura-godot3d-script-labirinto.png
: o script com o mapa de letras.../../../recursos/imagens/godot/chave-da-porteira-tela-chave.png
: as paredes com o jogo rodando.
Indicação da interface
| Item | Nome na tela |
|---|---|
| ver o labirinto | Executar Cena Atual com labirinto.tscn aberta |
| lista de nós criados enquanto o jogo roda | aba Cena, botão Remota |
O botão Remota aparece nas capturas do Módulo 10 (Aula 10.1).
O código completo
Trecho de scripts/labirinto.gd:
const TAMANHO := 3.0 # cada letra do mapa vira um quadrado de 3 m x 3 m
const ALTURA := 2.5 # altura das paredes, em metros
const MATERIAL_PAREDE := preload("res://materiais/taipa.tres")
## Lê o mapa letra por letra. A coluna vira X, a linha vira Z (o Y é a altura).
func montar_labirinto() -> void:
# Uma única malha e uma única forma de colisão servem para todas as paredes.
# Reaproveitar economiza memória: é a primeira regra de otimização.
var malha := BoxMesh.new()
malha.size = Vector3(TAMANHO, ALTURA, TAMANHO)
malha.material = MATERIAL_PAREDE
var forma := BoxShape3D.new()
forma.size = malha.size
for linha in MAPA.size():
for coluna in MAPA[linha].length():
var letra: String = MAPA[linha][coluna]
var lugar := Vector3(coluna * TAMANHO, 0, linha * TAMANHO)
match letra:
"#":
criar_parede(lugar, malha, forma)
"J":
jogador.position = lugar + Vector3(0, 0.1, 0)
"C":
chave.position = lugar + Vector3(0, 1.0, 0)
"P":
porteira.position = lugar
"S":
saida.position = lugar
func criar_parede(lugar: Vector3, malha: BoxMesh, forma: BoxShape3D) -> void:
var parede := StaticBody3D.new()
parede.position = lugar + Vector3(0, ALTURA / 2, 0)
var desenho := MeshInstance3D.new()
desenho.mesh = malha
var colisao := CollisionShape3D.new()
colisao.shape = forma
parede.add_child(desenho)
parede.add_child(colisao)
$Paredes.add_child(parede)
paredes += 1Explicação do código
MAPA[linha][coluna]pega uma letra: primeiro o texto da linha, depois a letra dentro dele.- A parede sobe metade da altura (
ALTURA / 2), porque a posição de uma caixa é o centro dela (como o cubo de 0,5 m da Aula 9.1). - As letras
J,C,PeSnão criam nada: só mudam o lugar de nós que já estão na cena. - Todas as paredes vão para dentro do nó
Paredes, para a árvore ficar organizada.
Resultado esperado
Labirinto próprio, desenhado em letras, montado pelo código e conferido pelo teste.
Problemas comuns
| Sintoma | Causa | Solução |
|---|---|---|
| "Invalid access" ou índice fora do limite | uma linha do mapa mais curta que as outras | todas as linhas com o mesmo número de letras |
| jogador nasce dentro da parede | mais de um J, ou J em cima de # | um só J, num chão |
| paredes flutuando ou enterradas | esqueceu o ALTURA / 2 | somar metade da altura no Y |
| dá para sair do labirinto pela borda | borda do mapa sem # | fechar a volta toda com # |
| não acha a porteira | a P não está num corredor de passagem obrigatória | conferir no papel (Parte A) |
Exercício guiado
Quantas paredes tem o labirinto do jogo? Conte os # sem abrir o Godot. (Resposta: 72. O teste confere que o número de paredes criadas é igual ao número de #.)
Desafio individual
Crie uma segunda letra de parede, M, que faz um muro baixo (metade da altura) com outro material.
Desafio avançado (opcional)
Coloque dois mapas no script e faça a tecla N trocar de labirinto, recarregando a cena.
Critérios de avaliação
- Mapa próprio, fechado e com caminho conferido.
- Explica linha → Z, coluna → X e a metade da altura.
- Explica por que reaproveitar a malha.
Checklist de conclusão
Extensão
Desenhe em letras o mapa da sua escola (salas, corredores, portas). Ele daria um bom labirinto?