零基础开发 era 游戏 #9 调试
学会「输入」和「输出」之后,基本上你就已经有能力制作自己的游戏了。
但在我们继续深入之前,先让我们系统学习一下如何「调试」你的游戏。
毕竟磨刀不误砍柴工。
Emuera 菜单#
无需开启调试模式也可以使用的功能,位于 Emuera 的菜单栏 > 第一个下拉菜单。
- 直接回到标题界面
- 快速重启
- 快速重新加载所有 erb 文件
- 重新加载指定目录
- 重新加载指定文件
这些虽然是无需启用调试模式的功能,不过大多数时候还是用作调试用途。
修改代码之后想更新到正在运行的游戏,重载就行。(实在不行也有一键重启)
不要手动关闭 Emuera 再启动啊,太憨了吧www。注意重载不等于重启。重载后,之前的代码仍会留在内存中,直到你不再调用它为止。
如何使用「分析模式」#
把 *.erb
文件拖到 Emuera 程序的可执行文件 ./Emuera*.exe
上,Emuera 会按照语法解析文件里的格式,生成 ./Analysis.log
报告日志。
调试命令#
需要将配置文件设置为 デバッグコマンドを使用する:YES
才能启用这个功能。
启用之后可以直接在 Emuera 主游戏窗口输入 @
开头的「调试命令」进行调试。
- 接变量名 / 行内函数名可以直接获得返回值。
- 接表达式可以直接对数据进行操作。
比如:
@MONEY = 10000
@PRINTV FLAG:200
@PRINTFORM %NAME:MASTER% 的 CFAG(1) 是 {CFLAG:MASTER:1}
@ADDCHARA 1
直接打印更具有可读性的字符串也是可以的:
@ @"当前 %NAME:MASTER% 的 CFAG(1) 是 {CFLAG:MASTER:1}。"
此外还有一些可以由调试命令唤起的功能:
@REBOOT
:重启 Emuera,emuera.config
、csv
、erb
文件都会被重新加载。@OUTPUT
:将当前的输出历史记录保存到emuera.log
。
如果文件已经存在,会覆写里面的内容。(与OUTPUTLOG
命令的行为相同)@EXIT
:退出 Emuera 程序。(与QUIT
命令的行为相同)@CONFIG
:打开设置界面。@DEBUG
:打开调试辅助工具窗口。(需要以调试模式启动)
如何启动「调试模式」#
快捷方式#
- 对一个可执行程序
Emuera*.exe
右键,选择「创建快捷方式」。 - 对刚刚新建的快捷方式右键,选择「属性」。
- 在「目标」一栏的 最后面 加上
-debug
(注意有空格)。 - 最后变成类似
***.exe -debug
这样的格式,保存。 - 之后使用这个快捷方式启动的 Emuera 就是调试模式了。
(窗口标题最后有(Debug Mode)
字样。)
但这种常规的方式设置步骤繁琐,而且并不能长久地通用。
比方说当你把整个项目文件夹移动到别的地方、或者更换了另一个版本的 Emuera 时,之前设置的快捷方式就会失效。
此时又需要重复一遍繁琐的设置,实在是很麻烦。
因此我们一般不采用这种方案。
脚本(批处理)#
这里提供一个通用的、压缩到一行的 快捷脚本。
在项目文件夹的根目录下「新建文本文档」,输入以下内容:
|
|
并保存,重命名为 *.bat
(比如 debug.bat
/ 调试模式.bat
)。
以后直接执行这个脚本就能自动以调试模式启动 Emuera 了。
理论上 兼容任何版本 的 Emuera,只要同级目录下有命名符合 Emuera*.exe
这个格式的可执行文件即可。
调试模式限定功能#
调试模式当然不是开着好看的,它的主要作用还是「
我们需要利用调试模式的各种功能,来帮忙监控代码的健康状态、排查出现的 bug。
单行代码#
Emuera(比起 eramaker 来说)新增了许多语法,其中一个对开发者来说非常重要的,可以说是「必知必会」的,就是 ;#;
。
以 ;#;
开头的那些行的代码只会在「调试模式」下执行。
这样就区分开了正常游戏流程和调试状态,调试完甚至可以不删除调试用的代码(当然,强烈建议不要这么做)直接发布,也不会影响到正常游戏。
@SYSTEM_TITLE ;#; CALL DEBUG_TEST_FUNC CALL RUN_MAIN_GAME QUIT @RUN_MAIN_GAME PRINTL 执行正常游戏流程 @DEBUG_TEST_FUNC $DEBUG_LOOP PRINTL 调试模式 测试新功能 INPUTMOUSEKEY GOTO DEBUG_LOOP
你也可以像上面这样,在不破坏正常游戏流程的前提下,「劫持」游戏运行流程,便于进行新功能的开发和测试。
类似的还有
;!;
,以此开头的行,只有 Emuera 才会运行(eramaker 不会)。
如果你只用 Emuera(不考虑兼容 eramaker)的话就没必要理会这个了。
多行代码#
[IF_DEBUG]
/ [ENDIF]
单行「仅限调试模式才会运行的代码」固然很好用,但也有它的局限性。
那就是写起来太麻烦了,每一行调试用代码都要在前面单独标注 ;#;
。
有时不想单独新建一个「调试用函数」,再 ;#; CALL
来进行调试;
就是想在已有的代码里面插入一长段「调试用代码」,应该怎么做呢?
此时可以使用 [IF_DEBUG]
/ [ENDIF]
标签。
拿之前《输入》一章里的「拆除炸弹」小游戏来举例:
@SYSTEM_TITLE WHILE 1 CLEARLINE LINECOUNT CALL DEFUSE_A_BOMB DRAWLINE PRINTW 再玩一遍? WEND QUIT @DEFUSE_A_BOMB #DIM answer ;#; #DIMS fuse, 3 = "红", "绿", "蓝" answer = RAND:3 [IF_DEBUG] PRINTL 调试模式已启用 PRINTFORML 正确的线是%fuse:answer%色 PRINTL [ENDIF] PRINTL 你要剪哪根线? SETCOLORBYNAME Red PRINTBUTTON "红色的线", 0 PRINT_SPACE 100 SETCOLORBYNAME Green PRINTBUTTON "绿色的线", 1 PRINT_SPACE 100 SETCOLORBYNAME Blue PRINTBUTTON "蓝色的线", 2 RESETCOLOR TINPUT 9999, -1, 1, "倒计时结束,炸弹爆炸了!" CLEARLINE 1 IF RESULT == answer PRINTL 你成功拆除了炸弹! PRINTL 获得成就「拆弹专家」。 ELSEIF RESULT != -1 PRINTL 你剪错了线,炸弹提前爆炸了! PRINTL 无人幸存。 ELSE PRINTL 无人幸存。 ENDIF
直接展示正确答案。
如此一来,无论调试是想故意复现「正确」还是「错误」的结果都可以随心所欲了。
[IF_NDEBUG]
/ [ENDIF]
与 [IF_DEBUG]
相反,还有 [IF_NDEBUG]
。
顾名思义,用这组标签包括起来的代码仅在「非调试模式」下才会运行。
有什么用呢?可以跳过正常游戏流程中设计的交互体验(固定桥段的演出)。
PRINTL 法宝炼化中…… [IF_NDEBUG] FOR RESULT, 1, 11 TWAIT 1000, 1 CLEARLINE 1 PRINTFORML 法宝炼化中……{RESULT*10}\% NEXT [ENDIF] IF RAND:2 PRINTL 法宝炼制失败 ELSE PRINTL 法宝炼制成功 ENDIF
这样写就只有正常游戏会进行「炼化过程」,调试模式会跳过等待的时间,直接获取结果。
[IF XXX]
/ [ELSEIF XXX]
/ [ELSE]
/ [ENDIF]
这里涉及到一个新概念:宏定义。
注意这里的「宏定义」是指 *.erh
文件中的 #DEFINE
功能。
区别于
./macro.txt
中设置的「宏命令」。
这组标签可以识别并判断是否定义(#DEFINE
)了某个「宏定义」。
头文件(当然你也可以起别的名字).erh
:
#DEFINE FIVE 5 #DEFINE HUNDRED 100
主要游戏流程(同上).erb
:
@SYSTEM_TITLE [IF ONE] PRINTFORML 存在名为 ONE 的宏定义 其值为 {ONE} [ELSEIF FIVE] PRINTFORML 存在名为 FIVE 的宏定义 其值为 {FIVE} [ENDIF] [IF HUNDRED] PRINTFORML FIVE_HUNDRED = {FIVE * HUNDRED} [ENDIF] QUIT
[SKIPSTART]
/ [SKIPEND]
类似 [IF_DEBUG]
之于 ;#;
,有时我们会想要注释一大段(连续多行)代码。
手动一行一行地加 ;
(分号)显然很累赘。
其实 VS Code 可以选中多行后使用组合键 Ctrl+/ 快速 注释 / 取消注释。
这时就可以用 [SKIPSTART]
/ [SKIPEND]
这组标签。
被这组标签包含在内的多行代码不会被 Emuera 读取 / 执行。
[SKIPSTART] 可以写多行的注释文本 PRINT 也可以用来注释多行代码 [SKIPEND] PRINT 对比正常运行的代码行 ; 对比单行注释
调试辅助工具窗口#
你大概已经注意到了使用调试模式启动 Emuera 后会弹出一个小小的窗口。
(调试模式下)关闭后可以使用 Ctrl+D 组合键重新打开。
它就是调试模式专属的辅助工具窗口。
菜单栏的两个菜单分别是「保存 / 读取
变量监控
点击「对象」一栏下方的空白区域,输入变量名,就将该变量加入监控列表了。
再点击右下角的「更新数据」按钮就可以刷新。
除了用了直接监控你想要随时查看的自定义变量之外,推荐加入一些常用的关键系统变量,比如:
LINECOUNT
:当前已经打印到渲染区域的行数RESULT
(RESULT:1
/RESULT:2
):系统内置的「返回值(数值)」RESULTS
(RESULTS:1
/RESULTS:2
):系统内置的「返回值(字符串)」- 等等
除此之外,你还可以直接监控「行内函数」的返回结果。
比如你有一个名为 @TEST_DEBUG
的行内函数(#FUNCTION
),就可以把 TEST_DEBUG()
加入监控清单,在「值」一栏会显示该函数的返回值。
但需要注意一点,这个功能每次刷新数据都会 调用 一次该函数,因此如果该函数带有其他副作用的话可能会造成难以预料的影响。
(比如一个联动角色血量的伤害计算函数,你每次刷新监控数据都会扣一次血。)
点击菜单栏第一个下拉菜单可以读取 / 保存这个列表。
除此之外,你也可以直接打开文本文件 ./debug/watchlist.csv
直接编辑监控列表。
堆栈跟踪信息
当前游戏执行到的堆栈位置信息,就是 警告 / 报错 时会显示的堆栈回溯信息。
这里可以随时观察到 Emuera 最新的堆栈状态,即使没有触发警告。
*実行中の行
ファイル名:main.erb
行番号:3 関数名:SYSTEM_TITLE
*スタックトレース
CALL :@SYSTEM_TITLE:main.erb:1行目
BEGIN:TITLE
控制台
上方输出
可以视为调试模式专属的「屏幕」,DEBUG 系列命令打印的信息会显示在这里。
注意 DEBUG 系无需在前面加
;#;
,它们本来就是只有调试模式才会执行的命令。
DEBUGCLEAR DEBUGPRINT 测试 DEBUGPRINT: DEBUGPRINTL 类似 PRINT DEBUGPRINTFORM 测试 %"DEBUGPRINTFORM"%: DEBUGPRINTFORML 类似 %"PRINTFORM"%
警告和报错信息也会显示在这里。
下方输入
「控制台」选项卡下方有一个可输入的文本框,类似主窗口的 调试命令,不过无论是否已经启用 デバッグコマンドを使用する
这个设置项都可以使用,而且不需要再加上 @
前缀。
- 可以在这里直接输入变量名,会返回该变量当前的值。
- 可以输入
RESULT = 123
这样的表达式直接对变量进行操作。
配置文件
这里详细讲解一下各项配置文件的作用,可交互的配置菜单对照着举一反三即可。
注意,以下设置项均保存在调试模式专属配置文件
./debug/debug.config
中。
在常规配置文件中./emuera.config
中新增是「无效」的。
一、起動時にデバッグウインドウを表示する
起動時にデバッグウインドウを表示する
是否在调试模式下启动自动显示调试窗口(而不需要 Ctrl + D 手动开启)。
二、デバッグウインドウを最前面に表示する
デバッグウインドウを最前面に表示する
启动后是否自动置顶显示调试窗口。
三、デバッグウインドウ幅
デバッグウインドウ幅
调试窗口宽度(包括窗口边缘)。
四、デバッグウインドウ高さ
デバッグウインドウ高さ
调试窗口高度(包括窗口边缘)。
五、デバッグウインドウ位置を指定する
デバッグウインドウ位置を指定する
是否指定调试窗口打开时的位置。
六、デバッグウィンドウ位置 X
デバッグウィンドウ位置X
启用「固定调试窗口位置」后,指定窗口出现的具体 X 位置。
七、デバッグウィンドウ位置 Y
デバッグウィンドウ位置Y
启用「固定调试窗口位置」后,指定窗口出现的具体 Y 位置。