有限状态机报错transition is invalid while previous transition is still in progress

在这之前,先来说下什么是有限状态机(Finite-state machine)

背景

我们在开发游戏,比如rpg游戏时,会涉及到玩家有各种状态,如攻击状态,等待状态等,如果用ifelse也可以实现,但是随着程序复杂度越来越高,这样肯定是不易于代码维护的,很容易出错,而且代码可读性比较差。这时,用状态机就可以很好的解决这些问题。我们可以通过状态机来记录它的各个状态(state)和状态之间的转换(transition),并且设置回调函数来做一些处理。

状态机特征

1.状态总数是有限的。
2.任一时刻,只处在一种状态中。
3.某种条件下,会从一种状态转变到另一种状态。

使用方法

把state-machine.min.js导入为cocoscreator插件,

var turnFsm = new StateMachine({
	init:'none',
    transitions: [
      { name: 'toStart', from: 'none',  to: 'start' },
      { name: 'playerTurn', from: 'start', to: 'player' },
      { name: 'enemyTurn', from: 'player', to: 'enemy' },
      { name: 'finish', from: 'enemy',    to: 'end' },
      { name: 'restart', from: 'end', to: 'start' }
    ],
    methods: {
      onStart: function() {
          console.log("onStart")
          turnFsm.playerTurn(); //错误示范,此时调用会报错
      },
      onPlayer: function(){
        console.log("onPlayer")
      },
      onEnemy: function(){
        console.log("onEnemy")
      },
      onEnd: function(){
        console.log("onEnd")
      }
      
    }
});

如上,定义了一个状态机,上边的状态机是用来控制回合制游戏每回合双方行动流程的
如从 none -> start开始行动 -> player玩家行动 -> enemy敌人行动 -> end行动结束

1.init为初始状态,设为none,(none是默认的初始状态,其实可以不用定义)
2.trainstions是来描述状态变化规则的数组,每一项是一个对象,

  • from:当前行为从哪个状态来
  • to:当前行为执行完会过渡到哪个状态
  • name:当前行为的名字

3.methods是定义的生命周期方法

方法 解释
onBeforeTransition 任何动作触发前触发
onBefore<TRANSITION> 在特定动作TRANSITION前触发
onTransition 在任何动作发生期间触发
onAfterTransition 任何动作触发后触发
onAfter<TRANSITION> 在特定动作TRANSITION后触发,可简写为on<TRANSITION>
onEnterState 当进入任何状态时触发
onEnter<STATE> 进入一个特定的状态STATE时触发,可简写为on<STATE>
onLeaveState 离开任何一个状态的时候触发
onLeave<STATE> 在离开特定状态STATE时触发

因此,对应以上定义的方法解释如下:

onStart //当进入start状态触发
onPlayer //当进入player状态触发
onEnemy //当进入enemy状态触发
onEnd //当进入end状态触发

注意:要想改变状态机的状态,就要调用transition方法,如
turnFsm.playerTurn(),才可以从start到player状态。

生命周期顺序
以playerTurn事件为例,从start状态到player状态,生命周期函数的发生顺序为:
onBeforePlayerTurn -> onLeaveStart -> onEnterPlayer -> onAfterPlayerTurn

常用方法

方法 解释
fsm.state 返回当前的状态
fsm.is(s) 返回bool值,表示当前状态机状态是否为 s
fsm.can(t) 返回bool值,表示过渡方法t是否可以从当前状态触发
fsm.cannot(t) 返回bool值,表示过渡方法t是否不能从当前状态触发
fsm.transitions() 返回从当前状态可以过渡到的过渡方法列表
fsm.allTransitions() 返回所有过渡方法的列表
fsm.allStates() 返回状态机所有状态的列表

示例:

onStart: function() {
	console.log("onStart")
    cc.log(turnFsm.state)
    cc.log(turnFsm.can("playerTurn"));
    cc.log(turnFsm.transitions());
    cc.log(turnFsm.allTransitions());
    cc.log(turnFsm.allStates());
    turnFsm.playerTurn(); //此时调用会报错
},

以上执行结果为:
在这里插入图片描述

报错信息

可以看到最后一行turnFsm.playerTurn();会报错

transition is invalid while previous transition is still in progress

报错信息截图如下:
在这里插入图片描述
上边报错的意思是此动作不可执行,因为之前的动作还在执行中。
从turnFsm.can(“playerTurn”)这个函数返回false就可以看出此时不能执行这个过渡方法。

解决方法
我们可以设置setTimeOut延时执行我们要执行的方法,这时,状态机会认为上一个transition已经执行完成

setTimeout(function(){
     cc.log("after 1s")
     cc.log(turnFsm.can("playerTurn")); //此时返回true
     turnFsm.playerTurn(); //此时可以正常执行下一个transition
 },1000);

可以看到,当延迟一秒之后,turnFsm.can(“playerTurn”)此时返回true,说明可以在这个时候正常调用下一个transition(playerTurn)。


如果还有其他方法可以规避此错误,欢迎补充~
发布了43 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_26542493/article/details/94338976
今日推荐