零基础开发 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.configcsverb 文件都会被重新加载。
  • @OUTPUT:将当前的输出历史记录保存到 emuera.log
    如果文件已经存在,会覆写里面的内容。(与 OUTPUTLOG 命令的行为相同)
  • @EXIT:退出 Emuera 程序。(与 QUIT 命令的行为相同)
  • @CONFIG:打开设置界面。
  • @DEBUG:打开调试辅助工具窗口。(需要以调试模式启动)

如何启动「调试模式」#

快捷方式#

  1. 对一个可执行程序 Emuera*.exe 右键,选择「创建快捷方式」。
  2. 对刚刚新建的快捷方式右键,选择「属性」。
  3. 在「目标」一栏的 最后面 加上  -debug(注意有空格)。
  4. 最后变成类似 ***.exe -debug 这样的格式,保存。
  5. 之后使用这个快捷方式启动的 Emuera 就是调试模式了。
    (窗口标题最后有 (Debug Mode) 字样。)

但这种常规的方式设置步骤繁琐,而且并不能长久地通用。
比方说当你把整个项目文件夹移动到别的地方、或者更换了另一个版本的 Emuera 时,之前设置的快捷方式就会失效。
此时又需要重复一遍繁琐的设置,实在是很麻烦。

因此我们一般不采用这种方案。

脚本(批处理)#

这里提供一个通用的、压缩到一行的 快捷脚本

在项目文件夹的根目录下「新建文本文档」,输入以下内容:

1
for /F "tokens=*" %%a in ('dir Emuera*.exe /B /O-D') do (start "" "%%a" -Debug & exit /B)

并保存,重命名为 *.bat(比如 debug.bat / 调试模式.bat)。
以后直接执行这个脚本就能自动以调试模式启动 Emuera 了。

理论上 兼容任何版本 的 Emuera,只要同级目录下有命名符合 Emuera*.exe 这个格式的可执行文件即可。

调试模式限定功能#

调试模式当然不是开着好看的,它的主要作用还是「调试debug」。
我们需要利用调试模式的各种功能,来帮忙监控代码的健康状态、排查出现的 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 组合键重新打开。

它就是调试模式专属的辅助工具窗口。

菜单栏的两个菜单分别是「保存 / 读取 监视变量清单watchlist.csv」和「调试窗口设置debug.config」。

变量监控

点击「对象」一栏下方的空白区域,输入变量名,就将该变量加入监控列表了。
再点击右下角的「更新数据」按钮就可以刷新。

除了用了直接监控你想要随时查看的自定义变量之外,推荐加入一些常用的关键系统变量,比如:

  • LINECOUNT:当前已经打印到渲染区域的行数
  • RESULTRESULT:1 / RESULT:2):系统内置的「返回值(数值)」
  • RESULTSRESULTS: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 位置。

lackbfun © 2021 - 2024