状态机与游戏破解¶
游戏破解状态机不仅必须保持内部状态,还必须根据该状态响应(或执行)游戏环境。整体游戏状态可能根据机器人的执行、其他玩家的行为以及游戏环境中其他不可预测的事件而改变。因此,试图基于观察到的游戏环境持久地走状态机是徒劳的;几乎不可能为每个状态创建一组转换,涵盖迭代之间可以做出的每一个可能观察。更合理的做法是让状态机每次考虑输入时都把游戏环境当作全新起点重新评估。要做到这一点,状态机必须使用游戏环境本身作为状态之间转换的机制——即机器人在环境上的执行应该对后续迭代产生足够影响,从而激活新状态。可以设计出能够这样工作的经典状态机,但我们将把它们扁平化,用更简单但依然非常强大的方式使用。
如果你熟悉经典状态机,这可能看起来不直观,但在接下来的章节中,你会看到状态机如何被改造并与控制理论配对,实现我们想要的。
主要区别在于,不是让一个状态仅仅激活另一个,对于游戏自动化状态机中的每个状态,机器人都会执行改变游戏整体状态、从而改变反馈回路下一次迭代检测到的状态的游戏内动作。在代码中,表示这个机器中状态的对象可能像这样:
class StateDefinition {
public:
StateDefinition(){}
~StateDefinition(){}
bool condition();
void reach();
};
你可以用简单的 std::vector 定义把 StateDefinition 对象组装成状态机,像这样:
瞧,你有了状态机的骨架,准备好接收你创建的任何 StateDefinition 对象。与反馈回路结合,这个状态机可以用来定义自动化的流程。
首先,你可以创建一组定义机器人期望行为的定义列表,按重要性在向量中排序。每个 StateDefinition 对象可以使用传感器信息作为输入,把这些数据传给 condition() 函数,确定状态是否应该被激活。然后,你可以创建一个控制器,遍历状态列表,调用 condition() 函数返回 false 的第一个状态的 reach()函数。最后,你可以把控制器包装在反馈回路中。如果你还不明白这个反馈回路如何工作,别担心;我现在就展示如何编写它。
注 你可以把 condition() 函数中的语句当作机器转换到下一个状态的要求。如果语句为 true,意味着在评估列表中下一个状态并继续循环之前,不必发生任何执行。如果语句为 false,意味着在转换发生之前,必须发生某种执行。
你会在本书源文件的 GameHackingExamples/Chapter11_St ateMachines 目录中找到下一节和第二百三十页「误差校正」的所有示例代码。随附项目可以用 Visual Studio 2010 编译,也应该能与其他任何 C++ 编译器一起工作。如果你想跟着做,请在 https://www.nostarch.com/gamehacking/ 下载并编译它们。