Ants Vs. SomeBees (C++ 版本) 介绍
下面有关游戏程序部分的内容,基于 v0.1.0-SeaOtter-patch.2 版本。
本博文刚建立时最新的版本是 v0.1.0-SeaOtter-patch.2,最终提交的产品版本是 v0.1.0-SeaOtter-patch.1。
本项目由于时间问题,未能提高项目的鲁棒性,因此错误的游戏方式可能导致不明原因的错误(如存档键值错误等等),即使是正确的游戏方式也无法保证一定不会出现问题。若有问题可前往 issue 进行反馈。
游戏背景
本项目是一个塔防游戏,基于 CS61A 项目作业 Ants Vs. SomeBees[1](Avsb),使用了 C++ 进行重新实现,同时增加了一些新的功能和特性。
做过 CS61A 项目作业的一下子肯定就知道具体内容了,不过这里还是会进行详细介绍。
基础概念
这个就是游戏界面了,虽然一目了然,但还是让我来依次介绍一下。
首先是最上面一排的功能按钮/信息块:
- Exit:退出按钮,会同时退出 Web GUI 和后端
- Restart:重启按钮,会回到游戏主界面,游戏当前内容会被放弃
- Save:浏览器会下载一个当前局面的 JSON 格式存档文件
- Food:显示当前食物数目
- Turn:显示当前轮数
然后是一排 16 个我方蚂蚁单位,具体细节会在稍后介绍。
每个蚂蚁单位上面是其名称,下面的数字是其食物消耗。顺序也是按照所需食物升序进行排列。不能够购买的蚂蚁单位是暗的,如上图因为食物只有 1,所以只有 Remover 这个单位是亮色的,可以进行部署。
下面则是具体进行游戏的地图,除了普通的陆地外还有湿地是特殊类型的位置单位。
就像植物大战僵尸一样,可以将蚂蚁单位部署在地图上,而蜜蜂会从右侧右侧的战争迷雾中出现,并向左边基地移动。同时当蜜蜂抵达地图最左边时,游戏失败。当所有蜜蜂被消灭时,游戏胜利。
有关地图的无关游戏的细节
这个游戏界面也许跟别的 CS61A 项目的实现并不一致。
实际上 CS61A 的项目作业一直在进行演化,光是我见过的 Web GUI 就有三种类型的了。其中一种是非 Web GUI,而且建模比较粗糙,就忽略不提了。另外一种就是我学 CS61A 时的项目了。
我做的时候除了上面一排、蚂蚁单位商店的样式有所不同外,最明显的差距就是没有战争迷雾,所有尚未出动的 Bee 一清二楚。这样有助于玩家掌握游戏进程,当然也少了一点刺激感。
最终我这个 Web GUI 是基于最新的(2024 Fall)CS61A 的 Web GUI 版本,这个后续会谈原因。
我方单位信息如下表所示:
形象 | 名称 | 食物消耗 | 血量 | 伤害 | 特殊 | |
---|---|---|---|---|---|---|
![]() |
Remover | 0 | 0 | x | 杀死选中位置上非 Queen 的蚂蚁。若对象是 Container,则只杀死 Container | |
![]() |
Harvest | 2 | 1 | 0 | 每轮收获一个单位的食物 | |
![]() |
Wall | 4 | 1 | 0 | - | |
![]() |
Long | 2 | 1 | 1 | 每轮攻击前方 5 格以后范围中的一个蜜蜂单位 | |
![]() |
Short | 2 | 1 | 1 | 每轮攻击前方 3 格以前范围中的一个蜜蜂单位 | |
![]() |
Thrower | 3 | 1 | 1 | 每轮攻击前方一个蜜蜂单位 | |
![]() |
Scuba | 6 | 1 | 1 | 抗水,每轮攻击前方一个蜜蜂单位 | |
![]() |
Slow | 4 | 1 | 0 | 每轮给予前方一个蜜蜂单位「缓慢」效果[2] | |
![]() |
Scary | 6 | 1 | 0 | 每轮给予前方一个蜜蜂单位「恐惧」效果[3] | |
![]() |
Guard | 4 | 2 | 0 | 是 Container,可以容纳一个非 Container 的蚂蚁单位 | |
![]() |
Tank | 6 | 2 | 1 | 是 Container,可以容纳一个非 Container 的蚂蚁单位,同时对当前位置所有蜜蜂单位造成伤害 | |
![]() |
Hungry | 4 | 1 | 0 | 每轮若不在咀嚼时,吃掉当前位置的一个蜜蜂单位,并咀嚼 3 轮[4] | |
![]() |
Fire | 5 | 3 | x (+ 3) | 受到攻击时,对当前位置所有蜜蜂单位进行等量伤害反射。死亡时额外附加伤害 | |
![]() |
Ninja | 5 | 1 | 1 | 每轮攻击当前位置所有蜜蜂单位,同时不会阻拦蜜蜂单位继续前进 | |
![]() |
Laser | 10 | 1 | 2 - f(x) | 每轮攻击前方所有昆虫单位,包括当前位置的 Container,伤害随距离与攻击次数增加而衰减[5] | |
![]() |
Queen | 7 | 1 | 1 | 抗水,每轮攻击前方一个蜜蜂单位,并给予后方所有蚂蚁单位加成[6]。只能有一个 Queen,Queen 死亡时游戏失败 |
敌方单位信息如下表所示:
形象 | 名称 | 伤害 | 特殊 |
---|---|---|---|
![]() |
Bee | 1 | - |
![]() |
Wasp | 2 | - |
![]() |
NinjaBee | 1 | 不会被阻拦 |
![]() |
Boss | 2 | 收到的伤害上限为 8,同时会被修正: |
上面的图片素材全部来源于 CS61A 项目,除了 Remover 都是拷贝自 2024 Fall 版本中的素材,Remover 来自我做的版本。
游戏打包
发布的是一个 Avsb.zip
的 ZIP 压缩包文件,将其解压到 ./Avsb
目录后就是游戏本体,其中包含四个文件或目录:
Avsb.exe
/Avsb
:游戏本体可执行文件(分别是 Windows 和 Linux 版,Windows 版有图标),支持直接打开或命令行运行static
:存储游戏所需的静态资源,包括图片、音频等templates
:存储游戏的 HTML 模板文件
后续可能将 templates
目录合并进 static
目录,同时可能将 Windows 和 Linux 分开打包。
实际上游戏体验没啥区别,所以下面以 Windows 为例。
命令行
-h
或 --help
选项获取帮助信息:
1 | ./Avsb.exe --help |
-v
或 --version
获得版本信息:
1 | ./Avsb.exe --version |
版本信息细节
常见的语义化版本采用的是 major.minor.patch
式版本,即主版本号、次版本号、修订号,而我并不是按这个来的。
虽然一开始确实有遵照语义化版本的意思,但是后面却追加了 patch,自然与语义化版本规范冲突了。
至于为啥要追加尾 patch 而非将第三个版本号上调呢?是因为我懒得发新版本……因为还没学 GitHub Action,而且用的是 XMake 构建工具,Windows 又要下载依赖什么的,比较麻烦,所以暂时还是手动发版。而要是上调版本号,我就还要发新版、写新的更新日志什么的,太麻烦了,就追加 patch 把之前的覆盖了
于是现在采用的是 primary.phase.build
,即主序号、阶段号、构建号。完整的版本信息则是 <primary>.<phase>.<build>-<codename>-patch.<patch>
,除了 patch 补丁号还多了一个 codename 代号。这个代号比较随意,没有明确的规范,我想怎么给就怎么给,但不会出现两个版本使用相同的代号的情况。
存档的版本不包括补丁号,所以会尽量让补丁不破坏存档的兼容性。不过 v0.1.0-SeaOtter-patch.1 与 v0.1.0-SeaOtter-patch.2 存档是不兼容的,因为存档版本的判断是 patch.2 引入的。
另外实际上真正的 v0.1.0-SeaOtter-patch.2 使用 --version
选项不会显示补丁号,这个是 patch.2 后面的 commit 追加的更新,不过因为不涉及程序、游戏等方面的内容,就没有加新号。
反正就是版本号非常混乱就是了。
-d
或 --difficulty
选项可调节难度,该选项与下面一个对攻击计划进行调节的选项冲突。
一共有 test
, easy
, normal
, hard
和 extra-hard
五个难度,默认是 normal
。难度会影响地图与敌方的攻击计划。
地图的长度是写死固定为 10 的,因为 CS61A 就是这么做的。在虚无飘渺的未来可能会加上自定义地图参数的支持。而宽度,test
难度是 1,easy
是 2,其余都是 4。
不过理论上可以通过修改存档自定义地图。但是因为并没有对其进行适配,可能会有问题。
从个人的角度出发也不建议用宽度小于 4 的地图,因为前端设计的是填充的,小于 4 效果会很丑陋。
敌方攻击计划细节
test
难度:
- 第 2 轮:1 只生命为 3 的 Bee
- 第 3 轮:1 只生命为 3 的 Bee
easy
难度:
- 第 3 轮:1 只生命为 3 的 Bee
- 第 4 轮:1 只生命为 3 的 Wasp
- 第 5 轮:1 只生命为 3 的 Bee
- 第 7 轮:1 只生命为 3 的 Bee
- 第 8 轮:1 只生命为 3 的 NinjaBee
- 第 9 轮:1 只生命为 3 的 Bee
- 第 11 轮:1 只生命为 3 的 Bee
- 第 13 轮:1 只生命为 3 的 Bee
- 第 15 轮:1 只生命为 3 的 Bee
- 第 16 轮:1 只生命为 15 的 Boss
normal
难度:
- 第 3 轮:2 只生命为 3 的 Bee
- 第 4 轮:1 只生命为 3 的 Wasp
- 第 5 轮:2 只生命为 3 的 Bee
- 第 7 轮:2 只生命为 3 的 Bee
- 第 8 轮:1 只生命为 3 的 NinjaBee
- 第 9 轮:2 只生命为 3 的 Bee
- 第 11 轮:2 只生命为 3 的 Bee
- 第 13 轮:2 只生命为 3 的 Bee
- 第 15 轮:2 只生命为 3 的 Bee
- 第 16 轮:1 只生命为 3 的 Wasp
- Boss 阶段
- 第 21 轮:2 只生命为 3 的 Bee
- 第 22 轮:2 只生命为 3 的 Wasp
- 第 23 轮:2 只生命为 3 的 Bee
- 第 24 轮:1 只生命为 1.5 的 Bee
- 第 25 轮:2 只生命为 3 的 Bee
- 第 26 轮:2 只生命为 3 的 NinjaBee
- 第 27 轮:2 只生命为 3 的 Bee
- 第 28 轮:1 只生命为 1.5 的 Bee
- 第 29 轮:2 只生命为 3 的 Bee
- 第 30 轮:1 只生命为 20 的 Boss
hard
难度:
- 第 3 轮:2 只生命为 4 的 Bee
- 第 4 轮:2 只生命为 4 的 Wasp
- 第 5 轮:2 只生命为 4 的 Bee
- 第 7 轮:2 只生命为 4 的 Bee
- 第 8 轮:2 只生命为 4 的 NinjaBee
- 第 9 轮:2 只生命为 4 的 Bee
- 第 11 轮:2 只生命为 4 的 Bee
- 第 12 轮:1 只生命为 2 的 Bee
- 第 13 轮:2 只生命为 4 的 Bee
- 第 15 轮:2 只生命为 4 的 Bee
- 第 16 轮:2 只生命为 4 的 Wasp
- Boss 阶段
- 第 21 轮:3 只生命为 4 的 Bee
- 第 22 轮:2 只生命为 4 的 Wasp
- 第 23 轮:3 只生命为 4 的 Bee
- 第 24 轮:1 只生命为 2 的 Bee
- 第 25 轮:3 只生命为 4 的 Bee
- 第 26 轮:2 只生命为 4 的 NinjaBee
- 第 27 轮:3 只生命为 4 的 Bee
- 第 28 轮:1 只生命为 2 的 Bee
- 第 29 轮:3 只生命为 4 的 Bee
- 第 30 轮:1 只生命为 30 的 Boss
extra-hard
难度:
- 第 2 轮:1 只生命为 2.5 的 Bee
- 第 3 轮:2 只生命为 5 的 Bee
- 第 4 轮:2 只生命为 5 的 Wasp
- 第 5 轮:2 只生命为 5 的 Bee
- 第 7 轮:2 只生命为 5 的 Bee
- 第 8 轮:2 只生命为 5 的 NinjaBee
- 第 9 轮:2 只生命为 5 的 Bee
- 第 11 轮:2 只生命为 5 的 Bee
- 第 12 轮:1 只生命为 2.5 的 Bee
- 第 13 轮:2 只生命为 5 的 Bee
- 第 15 轮:2 只生命为 5 的 Bee
- 第 16 轮:2 只生命为 5 的 Wasp
- Boss 阶段
- 第 21 轮:3 只生命为 5 的 Bee
- 第 22 轮:2 只生命为 5 的 Wasp
- 第 23 轮:3 只生命为 5 的 Bee
- 第 24 轮:1 只生命为 2.5 的 Bee
- 第 25 轮:3 只生命为 5 的 Bee
- 第 26 轮:2 只生命为 5 的 NinjaBee
- 第 27 轮:3 只生命为 5 的 Bee
- 第 28 轮:1 只生命为 2.5 的 Bee
- 第 29 轮:3 只生命为 5 的 Bee
- 第 30 轮:1 只生命为 30 的 Boss
-a
或 --plan
选项可指定外部攻击计划的 JSON 文件。
后续可能弃用 -a
,改用 -P
。
攻击计划 JSON 文件细节
下面是 normal
难度攻击计划的节选:
1 | { |
可以看出来,攻击计划的 JSON 中只有一个一级键 "waves"
,对应的值是一个对象,存储了攻击波次的具体信息。
攻击波次对象的键是数字(数字字符串),代表攻击的轮次。原则上小于时间的轮次不应出现在当前攻击计划中,即攻击计划是动态波动的。
轮次的键对应一个数组,成员为代表蜜蜂信息的对象。可以看出蜜蜂对象一共有五个键值对,分别代表其当前生命值、所处位置名称、恐惧状态剩余时间、缓慢状态剩余时间、类型。
攻击计划中的蜜蜂的所处位置,都应为蜂房,即 Hive
。
-w
或 --water
选项允许地图出现湿地,默认是没有湿地。
湿地位置细节
湿地的创建由 wetLayout
函数决定,该函数的定义如下:
1 | /** |
而 GameState::createLayout
的声明如下:
1 | /** |
因此可以看出,湿地的出现完全是固定的,没有随机因素。
而湿地频率这个值也是写死的 3,因为 CS61A 就是这么做的。不过后面也可能开放修改。只是如果开放了自定义地图,这个的意义就显得没这么大了。
-o
或 --open
选项以启动时自动打开 Web GUI,无法保证一定奏效。
另外如果已经打开了一个 Web GUI,该选项不会激活对应网页,而是会新打开一个,符合大部分程序 -o
及 --open
选项的行为。
该选项的具体实现
部分代码如下:
1 | string command; |
对于 Windows, macOS 与 Linux 平台,分别使用了 start
, open
与 xdg-open
命令以尝试打开网页。因此有可能不被支持。
不过在我这里,不管是 Windows11 还是 WSL Ubuntu 24.04,都可以正常打开网页,WSL 打开的是本机的网页。
-f
或 --food
选项可以指定开局的食物数目,默认是 2。
允许的范围就是 int
的范围,也就是说其实完全允许负数。只是小于 2 的初始食物数目会丧失游戏性,因为食物无法继续增长,甚至可能连移除蚂蚁单位都做不到。当然,如果是打算极限游玩定制的存档,那确实没问题,只不过这不是这个选项的管辖范围。
后续可能增加范围的限制?
-l
或 --log
选项设置日志的等级,共有 0, 1, 2, 3 四个选择。
游戏程序的信息大部分都有在日志中进行记录,显示的平台就是终端的 stdout——如果是直接启动的游戏程序,那就是在打开的那个(黑)框框上;如果是在终端命令行启动的,那就是在终端命令行。
日志一共有三个等级[7],按重要程度升序是 TEST[8], INFO 和 ERROR,与日志等级选项前三个对应。
因此设置日志等级的含义就是,只显示不低于设定等级的日志。因此默认的 1,即 INFO,就只会显示 INFO 及以上(INFO, ERROR)的日志信息。而 3,即 NONE 因为甚至大于 ERROR,所以连 ERROR 都不会显示。而我在调试测试过程中需要获得尽可能多的信息,就会选择 0,连 TEST 信息都会显示。
NONE 就一定不会显示所有日志信息吗?
并不是这样的。记录日志的 log
函数声明如下:
1 | /** |
可以看到其实有一个 force
选项,只要该选项为 true
,即使日志等级不够,也会强制进行显示。
这样做的原因是,这个记录日志的函数 log
其实不仅仅记录了游戏的日志信息,还会输出游戏前的一些问题,例如读取外部设置等。在这个操作过程中可能发生错误,但是此时还没有获得日志等级,就会出错。为了解决这个问题,我想了一个临时的解决方案,那就是不读取设置的显示日志等级,而是允许强制输出,这样就绕过了这个问题。
当然这个做法其实不太好,记录游戏日志的函数应当和程序本身信息的输出函数分开比较合适。
-p
或 --port
选项,设置 Web GUI 的端口,默认是 18080。
如果有端口冲突,可以使用此选项进行修改。
-c
或 --config
选项可以指定外部的设置 JSON 文件,默认会读取 ./config.json
[9]
设置的优先级是「命令行指定」>「设置文件」>「默认值」。
-s
或 --save
可以保存当前的设置到 ./config.json
。
例如说我调试的时候,要湿地,要设置食物为 999,要设置日志等级为 TEST,那我每次都要[10]
./Avsb.exe -w -f 999 -l 0 |
每次都这样,未免有点麻烦。虽然说在终端中可能可以 Up 来重复,但要是偶尔还要修改呢?或者执行了一些其他命令后又要启动了呢?
这时候就可以在后面加一个 -s
选项,直接保存这样的设置:
./Avsb.exe -w -f 999 -l 0 -s |
然后就会在工作目录上出现一个 config.json
文件。
当然这也会同时覆盖掉原有的 config.json
文件,如果有的话。后续可能会增加对于覆盖的确认,那可能还要加一个强制覆盖的选项,如 -S
什么的。
设置 JSON 文件细节
打开上面得到的 config.json
文件,会发现内容如下:
1 | { |
这就是设置的全貌了。
虽然一目了然,但还是逐个说明一下:
autoOpen
:布尔值,设置是否自动打开 Web GUIdifficulty
:字符串,设置难度initialFood
:整数,设置初始食物logLevel
:整数,设置日志等级planPath
:字符串,设置自定义攻击计划的路径port
:整数,设置端口waterEnabled
:布尔值,设置是否地图有湿地
基础功能
在弄清楚了游戏的基本概念和命令行后,下面会介绍一点游戏外部的基础功能。
运行游戏后,日志会显示:
其中左边的 [INFO]
代表这是 INFO 级别的日志,同时右侧链接有加粗,稍微好一点的终端,可以通过诸如 Ctrl/Alt + 单击的方式打开链接。另外这个虽然只有 INFO 等级,但是却是强制显示的。
这就是三种日志等级的样式了,TEST 是黄色,INFO 是蓝色,ERROR 是红色。
同时还有昆虫单位的信息:QueenAnt[34](1.00, Tunnel_1_3)
表示:
- 这是一个 QueenAnt 类型的昆虫单位。类名与名称并不一致,因此不是 Queen
- 唯一标识符(id)是 34
- 生命值是 1.00,保留两位小数
- 所在位置是 Tunnel_1_3,其中 1 代表纵坐标,3 代表横坐标,原点是地图左上角,都是从 0 开始计
即显示的昆虫信息模板是 type[id](health, place)
。
类名是绿色,生命值是洋红色,位置是青色。
类名与名称的关联
因为类名比较长,为了减少对于游戏界面显示空间的占用,在前端对类名进行了修正,具体代码节选如下:
1 | nameDiv.innerText = |
若是 BodyguardAnt,名称就为 Guard;若是 ThrowerAnt,名称就为 Thrower(删掉 Ant);否则就把 Thrower 或 Ant 的多余信息删掉。
是一个开发过程中赶时间的无奈之举。
颜色具体定义
1 | static const string ANSI_YELLOW = "\x1B[33m"; //!< 黄色 |
打开 Web GUI 后,主界面就是这样的。
对比 CS61A 的版本,多出了下面三个按钮。
四个按钮的具体功效是这样的:
- START:开始游戏
- LOAD:加载存档并进入游戏
- DOCS:显示文档(目前是已失效的 CS61A 项目文档,后续可能修改为本博文)
- CUSTOM:加载攻击计划(相当于命令行的
--plan
选项)
游戏界面中可以使用 Space 暂停或解除暂停。暂停的时候也可以按上面三个按钮进行对应操作。
不过暂停不意味着静止,即使暂停了,GIF 动图该动的还是会动,BGM 还是会放,在路途中的叶子还是会击中敌方,受到伤害还是会变红色。
前两个选项比较显而易见,下面来具体讲解一下存档的事情。
点击 Save 按钮后,浏览器会立刻下载存档 JSON 文件到下载目录。这个既有在紧张的游戏场景中避免因为选择路径而耽误时间的考虑,也有我懒的因素。
如上图所示,名称格式为 Avsb_save_<time>.json
,<time>
就是当前时间戳。
然后可以在主界面按 LOAD 按钮,并选择对应存档 JSON 文件读取恢复游戏。
恢复存档后的游戏状态一定与保存存档时的完全一致吗?
并不是!上面有提到过每个昆虫具有唯一标识符 id,这个重新加载存档并不会保持不变。其他的基本是和保存时一致。
存档 JSON 细节
下面是一个存档的示例节选,因为比较庞大,所以注解都以注释的形式写在里面了:
1 | { |
前端调试
这部分是有关前端调试方面的东西,比较底层与杂乱无章。可以折叠来跳过。
前端调试
静态资源文件都是暴露出来的,因此可以自行修改以满足需要。同时为了调试方便,也准备了一些预先定制的功能函数,以便在浏览器控制台进行调试。
然而因为时间比较紧张,前端代码比较混乱,没有进行代码复用,用两处的代码真的就是复制两遍。反正就是有各种问题,我后面完工后再测试前端的调试函数,似乎有点问题。反正就是不保证能用就是了。
主要提供的功能函数在 static/script.js
。首先在开头定义了一些变量:
1 | let enablePolling = true; |
首先需要对前后端交互的机制进行介绍,采用的就是普通的轮询机制,每隔一定时间(50ms),就会执行 updateStats
函数,前端向后端的 /update_stat
路由请求一下,然后后端就会返回当前的部分游戏状态(可购买的蚂蚁单位、食物数目、时间)。然后每隔更长的一段时间(5s),就会执行 insectsTakeActions
函数,向后端 /ants_take_actions
与 /bees_take_actions
请求一下,后端模拟一轮。
了解了这个后就可以看上面定义的变量了。enablePolling
表示当前是否正在轮询,默认是 true
。可以改为 false
以默认进入「单步调试」状态。剩下的变量最好不要动。
然后就是两个常量,轮询是比较消耗资源的,我看了看 CS61A 的项目,即使是结束了也还在不停地进行轮询。于是我就加入了自动停止的机制,在失败一定次数后,认定为断连,停止服务器,不再继续轮询。
这个值目前设置得比较大,因为比较小的话会很容易判定为断连。
然后就是提供的几个工具函数了:
1 | function manualUpdate() { ... } |
manualUpdate
函数执行updateStats
函数,手动更新游戏状态。如果不执行这个函数,前端显示的可能与后端不符manualInsectActions
函数执行insectsTakeActions
函数,手动进行一轮。可以用这个函数进行单步调试manualOneTurn
函数先执行一次insectsTakeActions
函数,再执行一次updateStats
,完成一轮并进行状态更新togglePolling
函数切换轮询状态
然后就可以开启调试模式,一步一步执行 manualInsectActions
或 manualOneTurn
推演,在原程序下断点跟踪或检测错误了,抑或是慢慢检查日志的信息。
当然,也可以以此把这个游戏当成是回合制游戏,可以等一轮完全准备好了[11],再使用 manualOneTurn
进入下一轮。
我虽然加入了关闭程序就同时终止服务器,停止轮询的代码,但是似乎并不奏效,还是要等到超时、请求失败积累而停止。所以说要关闭的话,顺手 Ctrl + W 把网页关闭,抑或是选择按 Exit 按钮进行退出比较合适。
该链接已失效,在每年课程周期也许会恢复。 ↩︎
缓慢状态下的蜜蜂单位,只会在偶数轮进行移动。一次缓慢效果的停滞时间为 3 次,可以叠加。 ↩︎
恐惧状态下的蜜蜂单位,会尝试返回蜂巢(若已到达地图最右侧,则不会继续返回蜂巢,而是会停留在原地)。一次恐惧效果的持续时间为 2 轮,不可叠加。 ↩︎
咀嚼一般可以直接杀死一个蜜蜂单位,但是对于有伤害修正效果的蜜蜂来说则不然。 ↩︎
。 ↩︎
被加成的蚂蚁单位,基础伤害翻倍。 ↩︎
没有 WARNING 等级,因为我也不知道哪里要警告,不如全 ERROR 了。 ↩︎
为什么不是 DEBUG 而是 TEST 呢?这是历史原因。一开始并没有提供给用户设置日志等级的选项,而是通过设置宏来决定日志等级,但 DEBUG 宏与编译调试部分的宏有冲突,虽然可以通过为宏名增加更清晰的注解,如 LOG_DEBUG,但最终还是选择了改名为 TEST,并沿用到现在。 ↩︎
相对的是工作路径,而非可执行文件的位置!如果是直接运行那二者没有区别。但如果是在命令行运行,工作路径不在可执行文件所在的目录(
PATH_TO_AVSB/Avsb
),那么这个相对的就是工作路径而非可执行文件的位置!按理来说相对可执行文件会比较合适,但我懒得做了,因为肯定比工作路径麻烦点。 ↩︎其实在实现外部设置之前,确实是这样做的。只是呢也不是手动输入,靠的是 VS Code 的设置,预先设置好了运行和调试的选项。 ↩︎
即使是暂停了轮询依旧可以部署、移除,放在湿地的非抗水蚂蚁单位依旧会立刻死亡。因为部署蚂蚁用的不是
/ants_take_actions
路由,不归insectsTakeActions
管,所以依旧会响应。不过我刚刚测试了一下,可能会有 500 Internal Server Error 问题,有机会可以研究一下。 ↩︎