有限状态机报错transition is invalid while previous transition is still in progress_烟雨星空的博客-程序员宅基地

技术标签: state-machine  状态机  cocos creator  

在这之前,先来说下什么是有限状态机(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)。


如果还有其他方法可以规避此错误,欢迎补充~
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_26542493/article/details/94338976

智能推荐

Android 显示 WebView ,加载URL 时,向webview的 header 里面传递参数_weixin_30603633的博客-程序员宅基地

1.主要布局 &lt;?xml version="1.0" encoding="utf-8"?&gt;&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" andro...

graphql是什么_为什么GraphQL是避免技术债务的关键_cumichun6193的博客-程序员宅基地

graphql是什么GraphQL (not to be confused with GraphDB or Open Graph or even an actual graph) is a remarkably creative solution to a relatively common problem: How do you enable front end developers to ac...

Windows下 C++ API函数大全_IT.Husky的博客-程序员宅基地_c++api

Windows下C++API函数大全,收藏起来了,需要的时候来检索

TestPattern error_、、、、南山小雨、、、、的博客-程序员宅基地

[mpegts @ 0x7f77740027c0] PES packet size mismatch[mpegts @ 0x7f77740027c0] Packet corrupt (stream = 1, dts = 84151592).read_time:126[h264 @ 0x7f7774022c00] error while decoding MB 64 29, bytestream -6againVread_time:3[aac @ 0x7f777402e780] decode_ba

spring源码解读二_溪枫小白的博客-程序员宅基地

上一篇文章说到了生命周期的初始化refresh方法在refresh里面有如下方法,这里只讲关键的几个方法比如说invokeBeanFactoryPostProcessors和finishBeanFactoryInitializationprepareRefresh();// Tell the subclass to refresh the internal bean factory....

SpringBoot集成Quartz实现动态定时任务_magic_1024的博客-程序员宅基地

SpringBoot集成Quartz实现动态定时任务,不停服务更新任务间隔

随便推点

java 执行 jar 包中的 main 方法_CGGAO的博客-程序员宅基地

java 执行 jar 包中的 main 方法首先来参考下打jar包的文档:https://jingyan.baidu.com/article/546ae1853f71a91149f28c85.html关于MANIFEST.MF详解。主要是Class-Path引入外包jar包,参考文档 如下:Class-Path: ext/mail.jar ext/activation.jar...

ffpmpeg 音量_有画面无声音 · Issue #2729 · bilibili/ijkplayer · GitHub_weixin_39552304的博客-程序员宅基地

刚开始播放一个影片的时候锁屏, 然后解锁, 这个时候有一定的概率出现有画面无声音的情况log如下:[IJKFFMoviePlayerController.m:411行]!!!!!!!!!!actual: ff3.2--ijk0.7.2-20161107--001expect: ff3.2--ijk0.7.4--20161116--001!!!!!!!!!!av_version_info: ff3....

内网穿透 微信设置_qq_40877660的博客-程序员宅基地

1.先修改WXController的appid和secret2.向getAccessToken发请求重新生成token,替换WXcontroller中access_token的属性值新的 token 在控制台下生成   有效期 7200s   2小时左右   时间过后重新生成 token  请求地址 http://8b42b630.ngrok.io/WXService/we

python 内置数据结构的基本操作 —— dict(2)_HeatDeath的博客-程序员宅基地

A mapping object maps hashable values to arbitrary objects. Mappings are mutable objects. There is currently only one standard mapping type, the dictionary. (For other containers see the built-in list,

python,day4,常用模块_一只地瓜a的博客-程序员宅基地

目录1、time模块2、random模块3、OS模块4、sys模块5、shutil模块6、json&amp;pickle模块7、shelve模块(了解)8、xml模块(了解)9、configparser模块10、hashlib 模块11、suprocess模块12、logging模块13、re模块1、time模块#一、time #时间分为三种格式: #1、时间戳:从1970年等到现在经历过的秒数 #用于时间间隔的计算

删除 Tomcat-webapps 目录自带项目_flyingaga的博客-程序员宅基地

删除 Tomcat-webapps 目录自带项目,如 docs、examples 等,并修改部分配置文件。提高 Tomcat 的运行性能和启动速度。

推荐文章

热门文章

相关标签