如果您曾经参与编程,那么您将熟悉错误的概念。 如果他们不打扰我们,那么开发过程将变得更快,更有趣。 但是这些错误只是在等待破坏我们的代码,工作进度和创意流程的时刻。 幸运的是,即使在复古游戏程序员的代码中,也有许多工具和策略可以消除错误。
调试工具
调试代码的最佳方法之一是使用调试器。 FCEUX和Mesen仿真器的某些版本具有内置的调试器,可让您随时中断程序以检查代码的运行状况。
FCEUX仿真器调试器值得注意的是,此方法更适合使用汇编语言的高级程序员。 但是我们是新手,所以我们将用C(cc65)编写。 当然,编译器将按照自己的规则运行,并且我们很难处理从C代码编译的机器代码。
十六进制编辑器FCEUX
假设我们需要观察某种变量或数组。
-Ln labels.txt
添加到链接器选项(ld65):-
-Ln labels.txt
编译项目后,
labels.txt
文件将出现在其文件夹中。 只需在用于查看文本的任何程序中打开它,然后查找我们要观察的变量的名称即可。
(
注意:如果声明了静态变量,则该变量将不包含在此列表中。因此, static unsigned char playerX
使用unsigned char playerX
代替static unsigned char playerX
unsigned char playerX
)
现在我们知道所需变量的地址,还不错。 让我们在调试器中找到它。 在FCEUX仿真器中运行ROM游戏。 在“调试”菜单中,选择“十六进制编辑器”,然后在打开的窗口中按Ctrl + G并输入变量的地址:
按确定,光标将移动到变量所在的地址。 让我们看一下:
这对于检查数组是否正确填充或跟踪特定变量的更改很有用。 此外,仔细观察您的代码,您会感觉像个老大哥。
查看其他有用的FCEUX仿真器Debug菜单工具,例如PPU Viewer,Name table Viewer等。
简化调试过程
如果我们不想每次都运行调试器来观察变量? 一种更高级的方法是编写一个将值显示在屏幕上的过程。 让我们尝试使用界面中的分数来显示玩家在Y轴上的位置:
完美的作品!
Retro-coder和
nesdoug博客所有者 Doug Fraker创建了一种类似的方法,用于将屏幕可视化用于调试目的。 下面显示的过程在屏幕上创建了一条灰色线,清楚地表明了CPU负载的程度:
您可以简单地将此过程复制到代码中,或将nesdoug.h库包含在项目中。 游戏周期结束后必须调用该过程,然后屏幕上将显示一个灰色条。
它起作用了,但是看起来我还有一个错误! 我们稍后将摆脱他。 同时,让我们继续前进。
宏的力量
宏也可以是有用的调试工具。 它们将使您能够在代码中找到已成为该错误源的位置。
让我们创建一种宏,它可以在正确的时间为我们提供信号,例如,播放声音或选择具有必要值的零调色板。 我们有几个宏可以将零调色板更改为红色,蓝色和随机颜色,并可以再现声音:
如何运作? 假设您已成功编译了一个项目,则使用游戏启动了仿真器,单击“开始”按钮,然后...
似乎只有白色的屏幕。 此外,某些仿真器可能会在状态栏中报告“ CPU卡塞!”。 接下来要做什么?
首先,您需要本地化发生错误的代码。 在这里,我的声音宏开始发挥作用。
我们肯定知道主菜单正在工作。 让我们看看之后会发生什么:
playMainMenu(); player.lives = 9; points = 0; gameFlags = 0; while(current_level<7 && player.lives>0) { set_world(current_world); debugSound; playCurrentLevel(); }
我怀疑
set_world
过程时游戏会崩溃。 让我们检查一下这种预感。 在检查完程序后,我只需在下一行输入宏名称。
我们开始该项目,然后……我听到声音了! 也就是说,此过程成功完成,我们需要检查以下内容:
playCurrentLevel
。 让我们将调试宏移到下面:
while(current_level<7 && player.lives>0) { set_world(); playCurrentLevel(): debugSound; }
我再次启动该项目,但听不到声音。 这意味着该过程尚未完成,并且内部发生故障。
在这种情况下,您应该打开过程代码并继续应用此技术,直到可以缩小搜索范围内可能的错误位置为止。
更改调色板的宏也可用于检查条件。 例如,我们的代码对以下几种情况执行复杂的测试:
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); }
如果在这里更改调色板的颜色,我们将查看条件是否满足:
这只鸡似乎还可以。 但是,如果该标志不起作用,则不满足条件之一。 在这种情况下,您需要分别检查它们,然后,也许会发现另一个错误。
核选项
我最近发现我游戏中的一个鬼魂表现出某种可疑的行为。 他不时拒绝攻击玩家。
看看这个被bug击中的幽灵-它仅在角色靠近屏幕中心时才会攻击:
无论我多么努力地研究此过程的代码,我都无法弄清楚该错误的隐藏位置,所以我决定采取极端措施并在现代开发环境中测试该代码的工作。
我拿走了我需要的所有东西:屏幕图,具有元文件属性的数组,过程代码,然后将它们简单地插入Visual Studio 2017中:
在PC上,代码的工作原理完全相同。 事实证明,该漏洞隐藏在一个程序中,该程序填充了缓存以查找玩家与敌人之间的障碍。 数组填充不正确。 我确定应该是0而不是0x80。
因此,我将尝试逐步调试代码以找出发生这种情况的原因。
这很有趣,但是看起来我按错误的顺序进行了操作。 让我们修复它,然后再次检查阵列!
现在看来该数组正在正确填充。 也就是说,我只需要修复cc65代码并再次编译NES项目即可。
因此,现代开发工具可以帮助调试算法和修复错误。
冷静地消除错误
错误很烦人,代码也很烦人。 保持镇定,不要失去控制,并使用所有可用工具来搜索和消除这些害虫。 您的代码质量和高枕无忧。
是否想直接从复古设计专业人士那里获得技巧? 欢迎来到我们的不和谐!
我们的游戏肉食在这里可用!