Se você já esteve envolvido em programação, está familiarizado com o conceito de bugs. Se eles não nos incomodassem, o processo de desenvolvimento se tornaria muito mais rápido e agradável. Mas esses bugs estão apenas esperando o momento de arruinar nosso código, horário de trabalho e fluxo criativo. Felizmente, existem muitas ferramentas e estratégias para matar bugs, mesmo no código dos programadores de jogos retro.
Ferramentas de depuração
Uma das melhores maneiras de depurar código é usar um depurador. Algumas versões dos emuladores FCEUX e Mesen possuem um depurador interno que permite interromper o programa a qualquer momento para verificar a integridade do código.
Depurador do emulador FCEUXVale ressaltar que esse método é mais adequado para programadores avançados que trabalham com linguagem assembly. Mas como somos novos, escreveremos em C (cc65). Obviamente, o compilador executará de acordo com suas próprias regras e será difícil lidar com o código de máquina compilado a partir do código C.
Editor hexadecimal FCEUX
Digamos que precisamos observar algum tipo de variável ou matriz. Adicione a seguinte linha às opções do vinculador (ld65):
-Ln labels.txt
Após compilar o projeto, o arquivo
labels.txt
aparecerá em sua pasta. Basta abri-lo em qualquer programa para visualizar textos e procurar o nome da variável que queremos observar.
(
Nota: se você declarou uma variável estática, ela não será incluída nesta lista. Portanto, em vez de static unsigned char playerX
use unsigned char playerX
)
Agora sabemos o endereço da variável desejada, não é ruim. Vamos encontrá-lo no depurador. Execute os jogos da ROM no emulador do FCEUX. No menu Debug, selecione o item Hex Editor e, na janela que se abre, pressione Ctrl + G e digite o endereço da nossa variável:
Pressione OK e o cursor se moverá para o endereço em que a variável está localizada. Vamos dar uma olhada nisso:
Isso pode ser útil para verificar se a matriz está preenchida corretamente ou para rastrear alterações em variáveis específicas. Além disso, você pode se sentir como um Big Brother, observando cuidadosamente seu código.
Confira outras ferramentas úteis do menu Debug do emulador FCEUX, como PPU Viewer, Name table Viewer, etc.
Simplifique o processo de depuração
E se não queremos executar sempre um depurador para observar uma variável? Uma maneira mais avançada é escrever um procedimento que exiba o valor na tela. Vamos tentar usar a pontuação na interface para exibir a posição do jogador no eixo Y:
Funciona perfeito!
Doug Fraker,
proprietário do blog de codificador
retroativo e
nesdoug , criou um método semelhante para usar visualizações na tela para fins de depuração. O procedimento mostrado abaixo cria uma linha cinza na tela que demonstra claramente o grau de carga da CPU:
Você pode simplesmente copiar este procedimento no seu código ou incluir a biblioteca nesdoug.h no projeto. O procedimento deve ser chamado após a conclusão do ciclo do jogo, e uma barra cinza será exibida na tela.
Funcionou, mas parece que tenho mais um bug! Vamos nos livrar dele mais tarde. Enquanto isso, vamos seguir em frente.
O poder das macros
As macros também podem ser uma ferramenta de depuração útil. Eles permitirão que você encontre um lugar no código que se tornou a fonte do bug.
Vamos criar algum tipo de macro que nos dará sinais no momento certo, por exemplo, tocar um som ou selecionar uma paleta zero com o valor necessário. Temos várias macros que alteram a paleta zero para vermelho, azul e cores aleatórias, além de reproduzir som:
Como isso funciona? Suponha que você tenha compilado um projeto com sucesso, inicie o emulador com o seu jogo, clique no botão Iniciar e ...
Parece não haver nada além de uma tela branca. Além disso, alguns emuladores podem relatar “congestionamento da CPU!” Na barra de status. O que fazer depois?
Primeiro, você precisa localizar o código no qual o erro ocorre. E aqui minha macro de som entra em cena.
Temos certeza de que o menu principal está funcionando. Vamos ver o que acontece depois:
playMainMenu(); player.lives = 9; points = 0; gameFlags = 0; while(current_level<7 && player.lives>0) { set_world(current_world); debugSound; playCurrentLevel(); }
Suspeito que o jogo trava quando o procedimento
set_world
é
set_world
. Vamos verificar esse palpite. Simplesmente insiro o nome da macro na próxima linha após a verificação do procedimento.
Começamos o projeto e ... ouço um som! Ou seja, esse procedimento foi bem-sucedido e precisamos verificar o seguinte:
playCurrentLevel
. Vamos mover a macro de depuração abaixo:
while(current_level<7 && player.lives>0) { set_world(); playCurrentLevel(): debugSound; }
Inicio o projeto novamente, mas não consigo ouvir um som. Isso significa que o procedimento não foi concluído e ocorre uma falha dentro dele.
Nesses casos, você deve abrir o código do procedimento e continuar a aplicar esta técnica até poder restringir sua pesquisa para uma possível localização de bug.
Uma macro de alteração de paleta também pode ser útil para verificar as condições. Por exemplo, nosso código executa um teste complexo de várias condições:
if ( (getTile(objX, objY+16) || collide16() ) || (objsOX[i] && objY>objsOX[i])) { debugRed; objsSTATE[i]=THWOMP_SMASH; objY=objsY[i]-=4; objsFRM[i]=0; sfx_play(SFX_THWOMP_SLAM_DOWN,2); }
Se mudarmos a cor da paleta aqui, veremos se a condição é satisfeita:
Esta galinha parece estar bem. Mas se a bandeira não funcionar, uma das condições não será atendida. Nesse caso, é necessário verificar todos eles separadamente e, talvez, você encontre outro erro.
Opção nuclear
Descobri recentemente que um dos fantasmas do meu jogo exibe algum tipo de comportamento suspeito. De tempos em tempos, ele se recusava a atacar o jogador.
Dê uma olhada neste fantasma atingido por um bug - ele só ataca quando o personagem está perto do centro da tela:
Não importava o quanto eu estudasse o código desse procedimento, não conseguia descobrir onde o bug estava oculto; por isso, decidi tomar medidas extremas e testar o trabalho desse código em um ambiente de desenvolvimento moderno.
Peguei tudo o que precisava: um mapa de tela, uma matriz com atributos de meta-arquivo, um código de procedimento e simplesmente os inseri no Visual Studio 2017:
No PC, o código funcionou exatamente da mesma maneira. Como se viu, o bug estava escondido em um procedimento que encheu o cache para encontrar obstáculos entre o jogador e o inimigo. A matriz foi preenchida incorretamente. Tenho certeza de que deve haver 0 em vez de 0x80.
Então, tentarei depurar passo a passo o código para descobrir por que isso está acontecendo.
É engraçado, mas parece que eu estava realizando as ações na sequência errada. Vamos corrigi-lo e verificar a matriz novamente!
Parece que agora a matriz está sendo preenchida corretamente. Ou seja, só preciso corrigir o código cc65 e compilar o projeto NES novamente.
Portanto, ferramentas modernas de desenvolvimento podem ajudar na depuração de algoritmos e na correção de bugs.
Livre-se dos bugs com calma
Os erros são irritantes, assim como o código irritante. Apenas fique calmo, não perca o controle e use toda a gama de ferramentas disponíveis para procurar e destruir essas pragas. A qualidade do seu código e a tranqüilidade aumentarão significativamente.
Deseja receber dicas diretamente de profissionais de design retro? Bem-vindo à nossa discórdia!
Nosso jogo The Meating está disponível aqui !