【问题标题】:Best way to implement a large state machine?实现大型状态机的最佳方式?
【发布时间】:2011-09-16 17:36:30
【问题描述】:

基本上我有一个控制游戏角色攻击的状态机,其时间基于动画长度。

例如:

我从默认状态开始,如果玩家点击攻击按钮,它会开始攻击,切换状态并根据攻击长度设置计时器。状态机变得更加复杂,但是当我考虑可以取消的冲锋攻击,可以根据击中的内容移动到不同状态的攻击,并且每个状态都有处理被攻击角色的独特方式时。 目前我有大量的 switch 语句。我考虑过多态性,但这需要为每个有很多状态的新类(例如,开始攻击、攻击和结束攻击都需要单独的状态)。

switch 语句有效,但它相当大,而且不像基于继承的系统那样容易修改。

对好看的实现有什么建议吗?

编辑: 这是使用java。

【问题讨论】:

    标签: java switch-statement state-machine


    【解决方案1】:

    对于较大的状态机,您必须注意“过渡爆炸”现象。事实证明,传统的有限状态机没有提供在许多状态之间重用公共转换的机制,因此您最终会重复太多并且您的状态机“爆炸”(这也违反了 Do-not-Repeat-Yourself ( DRY)原则)。

    出于这个原因,我建议使用分层状态机和实现技术,该技术可以轻松地将此类状态机映射到代码。有关分层状态机的更多信息,请参阅 Wikipedia 文章 http://en.wikipedia.org/wiki/UML_state_machine

    【讨论】:

      【解决方案2】:

      考虑构建一个表驱动的状态机。如果您考虑状态机的定义,您基本上有一组具有不同初始状态的 状态、一个转换函数,以及(在这种情况下)一个输入并输出字母。

      您可以构造一个按当前状态和输入索引的表,并使用指向函数或仿函数类的指针来表示发生的情况。该函数应该返回下一个状态。然后您可以将状态机构建为(伪代码):

       state := initial state
       while(state != STOP)
          state := (lookupTransition(inputs))()
      

      lookupTransition(inputs) 只是找到下一个状态。我在这里假设转换函数是没有参数返回状态的函数,所以lookupTransition(inputs) 必须是一个函数,无论你有多少输入,返回一个指向返回状态的 void 参数函数的指针。

      正确设置,可以将所有状态机和行为放到一张表中,方便修改和重新编译。

      (为了获得额外的荣誉,请弄清楚如何从文件中加载该表,因此您根本不需要重新编译。)

      更新

      在 Java 中,使用仿函数类代替函数指针。

      另一个更新

      当然,另一种选择是使用像Ragel 这样的状态机编译器。

      【讨论】:

      • 这才是真正的问题,不是吗。一旦您需要为每个状态/事件组合创建一个新类,代码就会变得非常冗长。我们必须等待关闭才能最终能够简洁地做这些事情。目前,可以使用反射或代码生成来减少代码混乱,但它们都有自己的缺点。
      • 你知道,老实说,我怀疑这里存在本质上的复杂性。每次转换时,闭包只会帮助一两行;使用仿函数使代码有点千篇一律,但复杂性并没有那么不同。使用动态语言,如 Ruby、Python 或 Groovy,可能会有所帮助,但主要是因为它会使表格加载部分更容易。但最终,如果你有一个复杂的状态机,你将不得不编写代码。
      【解决方案3】:

      Boost 有一个完美的状态机,唯一的缺点是习惯了模板/类型编程

      http://www.boost.org/doc/libs/1_46_1/libs/statechart/doc/index.html

      【讨论】:

      • 我习惯于模板编程,但是我目前正在使用 java,我可能应该提到这一点。
      【解决方案4】:

      在我身边,我正在使用 stateforge 一个 HFSM(http://www.stateforge.com/)。 并行状态,分层方法和观察者可以解决相当多的复杂情况。

      【讨论】:

        【解决方案5】:

        我不能说我曾经使用过它,但有http://commons.apache.org/scxml/。使用其他人建议的基于表格的方法,手写也不是那么难。

        【讨论】:

          猜你喜欢
          • 2011-01-09
          • 1970-01-01
          • 1970-01-01
          • 2013-01-04
          • 2021-07-02
          • 2011-03-30
          • 2016-06-14
          • 1970-01-01
          • 2010-09-13
          相关资源
          最近更新 更多