Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 实现大型状态机的最佳方法?_Java_Switch Statement_State Machine - Fatal编程技术网

Java 实现大型状态机的最佳方法?

Java 实现大型状态机的最佳方法?,java,switch-statement,state-machine,Java,Switch Statement,State Machine,基本上,我有一个控制游戏角色攻击的状态机,根据动画长度计时 例如: 我从默认状态开始,如果玩家点击攻击按钮,它就会开始攻击,切换状态并根据攻击长度设置计时器。状态机变得更加复杂,但是当我考虑可以被取消的攻击攻击时,可以根据它们所击中的目标移动到不同的状态,并且每个州都有独特的方式来处理被攻击的角色。 目前我有大量的switch语句。我考虑过多态性,但这需要为每个状态创建一个新的类,其中有很多状态(例如,开始攻击、攻击和结束攻击都需要单独的状态) switch语句可以工作,但是它相当大,并且不像基

基本上,我有一个控制游戏角色攻击的状态机,根据动画长度计时

例如:

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

switch语句可以工作,但是它相当大,并且不像基于继承的系统那样容易修改

对美观的实现有什么建议吗

编辑:
这是在使用java。

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


考虑构建一个表驱动的状态机。如果你想一想状态机的定义,你基本上有一组状态,有一个可分辨的初始状态,一个转换函数,以及(在本例中)一个输入和输出字母表

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

其中
lookupTransition(inputs)
只查找下一个状态。我在这里假设转换函数是无参数返回状态的函数,因此
lookupTransition(inputs)
必须是有多少输入的函数,返回指向返回状态的无效参数函数的指针

正确地设置它,您可以将所有状态机和行为放在一个表中,该表可以轻松地修改和重新编译

(为了获得额外的积分,请找出如何从文件加载该表,这样就根本不需要重新编译。)

更新

在Java中,使用类似于函子类的东西来代替函数指针

另一次更新


当然,另一种选择是使用状态机编译器,比如。

我不能说我曾经使用过它,但确实有。使用其他人建议的基于表格的方法,手工书写也不难

对于较大的状态机,您必须注意“过渡爆炸”现象。事实证明,传统的有限状态机不提供跨多个状态重用公共转换的机制,因此您最终会重复太多,并且您的状态机“爆炸”(这也违反了请勿重复自己(DRY)原则)


出于这个原因,我建议使用分层状态机和实现技术,允许轻松地将这些状态机映射到代码。有关分层状态机的更多信息,请参阅Wikipedia文章

在我这边,我正在使用stateforge和HFSM()。
并行状态、分层方法和观察者可以解决相当多的复杂情况。

我习惯于模板编程,但我目前使用java,我可能应该提到这一点。这才是真正的问题,不是吗。只要您需要为每个状态/事件组合创建一个新类,代码就会变得非常冗长。我们将不得不等待结束,以最终能够做这样的事情简洁。目前,反射或代码生成可以用来减少代码混乱,但也有其自身的缺点。每个转换只有一行或两行闭包有帮助;使用函子使代码有点像饼干刀,但复杂性并没有那么大的不同。使用动态语言,如Ruby、Python或Groovy,可能会有所帮助,但主要是因为它会使表加载部分更容易。但最终,如果你有一个复杂的状态机,你将不得不编写代码。
 state := initial state
 while(state != STOP)
    state := (lookupTransition(inputs))()