一个复杂的假设状态机¶
治疗状态机实现的行为很简单,所以把它卷入这种控制结构可能看起来小题大做,但如果你想扩展控制器,它很有用。例如,如果你想治疗状态机与我在第二百二十二页「控制理论与游戏破解」中讨论的「行走、攻击、搜刮」行为结合,控制结构会复杂得多。让我们高层看看你需要的状态:
强治疗:生命值超过 50% 时条件满足。达成方式是施放强治疗法术。
弱治疗:生命值超过 70% 时条件满足。达成方式是施放弱治疗法术。

攻击法术:没有可用目标或攻击法术在冷却时条件满足。达成方式是向目标施放攻击法术。
放风筝怪物:没有可用目标或与目标距离足够时条件满足。(「足够」的定义取决于放风筝时你想离敌人多远。)达成方式是向远离目标的方向迈出一步。
瞄准怪物:没有可攻击的生物时条件满足。达成方式是攻击一个生物。
搜刮物品:没有打开的尸体或打开的尸体没有可搜刮物品时条件满足。达成方式是从打开的尸体取走物品。
接近尸体:没有可打开的尸体或与尸体相邻时条件满足。达成方式是向将要打开的尸体迈出一步。
打开尸体:角色与可打开的尸体不相邻时条件满足。达成方式是打开相邻尸体。
跟随路径:角色无法移动到当前航点或站在当前航点上时条件满足。达成方式是向当前航点迈出一步。
推进航点:没有剩余航点可跟随时时条件满足。达成方式是把当前航点更新为列表中下一个航点。如果角色出于某种原因(比如卡住)无法到达当前航点,推进航点状态防止它被卡住。如果角色已到达当前航点,推进航点选择下一个航点保持前进。
这个状态机比纯治疗状态机复杂得多。如果我画出这个状态机,图中会有 23 个对象,箭头跨越 33 条控制路径。把它与图 11-3 比较,后者只有 7 个对象和 9 条控制路径。
你可以在不使用状态机或反馈回路的情况下编写治疗者行为,但我无法想象如何轻松地为这个功能完整的机器人做到同样的事。这 10 个状态中的每一个不仅依赖自己的条件,还依赖它前面每个状态的条件。此外,硬编码逻辑要么需要大量嵌套的 if() 语句,要么需要一堆堆叠的 if()/return() 语句——无论哪种方式,它都只是表现得像状态机,但没有运行时灵活性。
运行时灵活性指的是状态机变异的能力。与硬编码条件检查不同,状态机中的状态定义可以动态移动、移除和添加。状态机方法允许你根据用户输入即插即用不同的行为和功能。
要更进一步,你可以向 Lua 环境暴露传感器和执行器,创建能够从状态机添加和移除状态的 Lua 函数,并修改 StateDefinition,让它的 condition() 和 reach() 函数可以调用 Lua 环境暴露的 Lua 函数。这样编写控制系统,你可以用 C++编写机器人核心(钩子、内存读取、执行),同时让 Lua(一种高级动态语言)可用于自动化。
注 你可以通过在程序中包含几个头文件并链接 Lua 库来嵌入 Lua。这个过程不难,但超出了本书范围,所以我鼓励你查看 Roberto Ierusalimschy 的《Lua 程序设计》第 24 章(http://www.lua.org/pil/24.html)了解更多信息。