Módulo 10 · Aula 10.1 · Caça aos erros: mensagens, print e pontos de interrupção
| Carga horária | Dificuldade | Ferramenta | Competências |
|---|---|---|---|
| 10 h/a | ⭐⭐⭐ | Godot 4.7 | C2, C5 |
Objetivos de aprendizagem
- Ler uma mensagem de erro do Godot: o que deu errado, em que arquivo e em que linha.
- Usar
printpara ver valores enquanto o jogo roda. - Parar o jogo numa linha com um ponto de interrupção e olhar as variáveis.
- Separar erro de execução (o jogo para) de erro de lógica (o jogo roda, mas faz a conta errada).
Pré-requisitos
Módulo 8.
Materiais
Godot 4.7; projeto exemplos/caca-aos-erros (sem a pasta gabarito, que fica com o professor).
Conceitos
O caixa da feira. O projeto tem um script só, caixa.gd, que soma um pedido (cuscuz R$ 3,50, tapioca R$ 5,00, suco R$ 4,00), calcula o troco de R$ 20,00 e escreve em reais. Ele tem quatro erros escondidos, de propósito. O certo seria:
Conta: R$ 12,50
Troco de R$ 20,00: R$ 7,50
Uma tapioca e um suco: R$ 9,00Rodando o projeto como ele está, sai isto (cópia de uma execução real, sem janela):
Conta: R$ 9,0
Troco de R$ 20,00: R$ -11,0
SCRIPT ERROR: Invalid access to property or key 'Suco' on a base object of type 'Dictionary'.
at: total (res://scripts/caixa.gd:26)
GDScript backtrace (most recent call first):
[0] total (res://scripts/caixa.gd:26)
[1] _ready (res://scripts/caixa.gd:19)
Uma tapioca e um suco: R$ 0,0Como ler a mensagem de erro. Três partes, sempre:
| Parte | Neste caso | Quer dizer |
|---|---|---|
| o que aconteceu | Invalid access to property or key 'Suco' ... 'Dictionary' | pediu ao dicionário uma chave Suco que ele não tem |
| onde | total (res://scripts/caixa.gd:26) | função total, linha 26 |
| quem chamou | _ready (res://scripts/caixa.gd:19) | foi a linha 19 que chamou total |
As mensagens do Godot são em inglês, mesmo com o editor em português. Vale ter um glossário na parede: invalid (inválido), access (acesso), key (chave), null instance (nó que não existe), nonexistent function (função que não existe).
Erro de execução × erro de lógica.
| Tipo | Como aparece | Exemplo no caixa |
|---|---|---|
| execução | o Godot para e mostra mensagem vermelha | 'Suco' com S maiúsculo |
| lógica | o jogo roda, mas o resultado está errado | conta de R$ 9,00 em vez de R$ 12,50 |
O erro de lógica é mais traiçoeiro: ninguém avisa. Só aparece quando alguém sabe qual era o resultado certo. Por isso o primeiro passo de qualquer teste é escrever o que deveria acontecer.
print. O jeito mais simples de espiar: print("i = ", i, " soma = ", soma) dentro da repetição mostra cada volta na Saída.
Ponto de interrupção (breakpoint). Clicando à esquerda do número da linha, aparece uma bolinha vermelha. Rodando pelo editor, o jogo para antes daquela linha, e o painel Depurador mostra as variáveis naquele instante. Com os botões do depurador, dá para andar uma linha de cada vez.
Quando o editor para sozinho. Rodando pelo editor, um erro de execução também para o jogo, igual a um ponto de interrupção: o depurador abre na linha do erro, com as variáveis à mostra (primeira captura).
Exemplos
O que a captura do ponto de interrupção mostra, parado na linha 26 na primeira volta:
| Variável | Valor | O que ela revela |
|---|---|---|
itens | Array (tamanho 3) | o pedido tem 3 itens |
soma | 0 | nada foi somado ainda |
i | 1 | a primeira volta já começou no item 1, e não no 0: o cuscuz ficou de fora |
Tutorial passo a passo
Parte A. Prever antes de rodar (40 min)
- Abra
scripts/caixa.gd. Sem rodar, calcule à mão os três resultados certos e anote no caderno.
Parte B. Rodar e ler (80 min)
- Executar Projeto. O editor para e abre o Depurador na aba Rastreamento de Pilha, com a mensagem em vermelho e a linha 26 marcada (captura).
- Leia a mensagem com a tabela dos Conceitos. Que item causou o erro? Qual linha chamou?
- Pare o jogo. Na aba Saída, compare as duas primeiras linhas com o que você calculou.
Parte C. Ponto de interrupção (120 min)
- Clique à esquerda do número 26 (ou deixe o cursor na linha e use Alternar Ponto de Interrupção, tecla F9). Aparece a bolinha vermelha.
- Rode de novo. O jogo para na linha 26. Olhe o quadro Locals (em inglês na tela):
ivale quanto? - Use o botão de avançar no depurador (Continuar) e veja
somaeimudarem a cada volta. - Ache o erro 1 e corrija. Rode de novo.
Parte D. print e os outros erros (160 min)
- Para o troco, ponha
print("pago = ", pago, " conta = ", conta)dentro detroco. Ache o erro 2. - Para o formato, teste
reais(1205). Deveria dar R$ 12,05. Ache o erro 3 (dica: compare com a funçãoreaisda Feira do Troco, Aula 8.8). - Corrija o erro 4 (o que derrubava o jogo).
- Rode tudo e compare com o que você calculou no passo 1. Apague os
printde investigação.
Parte E. Registro (100 min)
- No diário, para cada erro: sintoma, como achou (mensagem,
printou ponto de interrupção), causa e correção.
Imagens
../../../recursos/imagens/godot/captura-godot-depurador-erro.png
: o editor parado no erro, com a mensagem Invalid access ... 'Suco', a pilha (linhas 26 e 19) e as variáveis.../../../recursos/imagens/godot/captura-godot-depurador-ponto-de-interrupcao.png
: parado no ponto de interrupção da linha 26, com i = 1,soma = 0e a lista Pontos de Interrupção mostrando "Linha 26".
Indicação da interface
| Item | Nome na tela (Godot 4.7.2 em português) |
|---|---|
| painel de baixo | Saída, Depurador (com o número de erros: Depurador (1)) |
| abas do Depurador | Rastreamento de Pilha, Erros, Executor, Analisador, Analisador Gráfico, Monitores, Memória de Vídeo |
| quadros do Rastreamento de Pilha | Quadros de Pilha, Filtrar Variáveis de Pilha, Locals (em inglês), Pontos de Interrupção |
| marcar a linha | Alternar Ponto de Interrupção (menu Depuração do editor de script, tecla F9) |
| botões do depurador | Entrar, Ignorar, Pausar, Continuar (dicas dos botões) |
| ver nós do jogo rodando | aba Cena, botões Remota e Local |
| ao parar o jogo | aviso "Sessão de depuração fechada." |
Os nomes das abas, dos quadros, de Remota e Local aparecem nas capturas. Alternar Ponto de Interrupção e as dicas dos botões foram lidos das traduções do Godot 4.7.2. A tecla F9 vem da documentação do Godot e não foi conferida.
O código completo
scripts/caixa.gd (com os erros):
extends Node
## Caixa da barraca de comida da feira (Aula 10.1).
## ATENÇÃO: este script tem 4 erros escondidos, de propósito. A turma vai achar todos
## lendo as mensagens do Godot, usando print e pontos de interrupção.
## Preços em centavos, como na Feira do Troco: R$ 3,50 vira 350.
const PRECOS := {
"cuscuz": 350,
"tapioca": 500,
"suco": 400,
}
func _ready() -> void:
var pedido := ["cuscuz", "tapioca", "suco"]
var conta := total(pedido)
print("Conta: ", reais(conta))
print("Troco de R$ 20,00: ", reais(troco(2000, conta)))
print("Uma tapioca e um suco: ", reais(total(["tapioca", "Suco"])))
## Soma o preço de todos os itens do pedido.
func total(itens: Array) -> int:
var soma := 0
for i in range(1, itens.size()):
soma += PRECOS[itens[i]]
return soma
## Quanto devolver para quem pagou "pago" por uma conta de "conta".
func troco(pago: int, conta: int) -> int:
return conta - pago
## Escreve 1250 como "R$ 12,50".
func reais(centavos: int) -> String:
return "R$ %d,%d" % [floori(centavos / 100.0), centavos % 100]O gabarito, com um comentário em cada correção, está em gabarito/caixa_corrigido.gd.
Explicação do código
Gabarito dos quatro erros (para o professor):
| Erro | Linha | Problema | Correção |
|---|---|---|---|
| 1 | 25 | range(1, ...) começa no segundo item | for item in itens: |
| 2 | 32 | conta - pago dá troco negativo | pago - conta |
| 3 | 37 | %d mostra 5 centavos como ,5 | %02d (dois dígitos, completa com zero) |
| 4 | 19 | "Suco" maiúsculo não existe no dicionário | "suco" |
Repare: o erro 4 só apareceu porque o erro 1 pulou o primeiro item e foi direto no segundo, "Suco". Erros escondem outros erros. Por isso se corrige um de cada vez e se roda de novo.
Resultado esperado
Os quatro erros achados e corrigidos, cada um com o registro de como foi achado. O teste automático (testes/godot/testar_caca_aos_erros.gd) confere, no gabarito, os resultados R$ 12,50, R$ 7,50, R$ 9,00, R$ 12,05 e R$ 0,05.
Problemas comuns
| Sintoma | Causa | Solução |
|---|---|---|
| o ponto de interrupção não para | rodou o jogo exportado ou sem ser pelo editor | rodar pelo editor |
| o jogo "trava" e não volta | está parado num ponto de interrupção | Continuar no depurador, ou tirar a bolinha |
| corrigiu e o erro continua | não salvou o script | Ctrl+S antes de rodar |
| apareceu outro erro depois de corrigir | um erro escondia o outro | normal; um de cada vez |
print não mostra nada | a linha nunca é executada | é uma pista: o código não passa por ali |
Exercício guiado
Por que o primeiro passo foi calcular os resultados à mão, antes de rodar? (Resposta: erro de lógica não dá mensagem; só dá para saber que a conta de R$ 9,00 está errada se alguém souber que o certo é R$ 12,50.)
Desafio individual
Esconda um erro de lógica no seu Projeto 6 (numa cópia), troque com a dupla e cronometre quanto tempo cada um leva para achar o do outro.
Desafio avançado (opcional)
Escreva um teste automático para o caixa corrigido, no mesmo estilo de testes/godot/testar_caca_aos_erros.gd, com três pedidos novos.
Critérios de avaliação
- Lê a mensagem de erro dizendo o quê, onde e quem chamou.
- Usa ponto de interrupção e lê as variáveis.
- Registro dos quatro erros com sintoma, método, causa e correção.
Checklist de conclusão
Extensão
Procure nos seus projetos antigos um print esquecido. Ele atrapalha o jogo? E se o jogo for publicado?