Quick StateMachine状态机

状态机在quick中是一个亮点,如果我们做一款RPG游戏,一个角色一般会拥有idle,attack,walk,run,death这些状态,如果游戏角色的状态采用分支条件判断的话,会造成非常庞大而难以维护,但一旦使用了状态机这种模式,就会显得简单方便。

对于quick中的状态机是如何实现的咱们先不去了解,首先看看如何去使用它。

总结起来,如果让一个类拥有状态机,主要有两步:

1.创建状态机对象

2.初始化状态机,主要包括事件和回调函数

1.创建状态机组件

self.fsm = {}
cc.GameObject.extend(self.fsm):addComponent("components.behavior.StateMachine"):exportMethods()

这样就创建了一个状态机对象,接下来我们要对其初始化,其实也就是设置各个状态的逻辑。

2.初始化状态机(设置状态逻辑)

设置状态逻辑是重写setupState方法,这其中有这么几个字段参数,

  • initial:状态机的初始状态
  • terminal (final):结束状态
  • events:状态发生转变时对应的事件
  • callbacks:发生转变时的回调函数

一般我们会设置initial,events和callbacks这三个。

先看events,在events中需要分清楚“事件”和“状态”,events采用table结构,例如我们来写一个

events = {
      {name = "move", from = {"idle", "jump"}, to = "walk"},
}

这其中move是事件,就像触摸事件event.name那样,name表示事件名称,而from和to后面跟的idle,jump,walk表示状态。所以上面的意思就是,当执行move事件时,如果状态是idle或者jump,那么都会跳转到walk状态上。

from的状态可以是单一状态,也可以使集合状态,就是几个状态,但to的状态只能唯一,不然程序还给你来个随机状态?肯定不行的。

所以这里需要想好我们的主角有哪些状态,当什么事件发生时,他会从什么状态变到什么状态上去。例如我简单这么写,

events = {
	{name = "move", from = {"idle", "jump"}, to = "walk"},
	{name = "attack", from = {"idle", "walk"}, to = "jump"},
	{name = "normal", from = {"walk", "jump"}, to = "idle"},
},

解释一下,如果是normal事件,不管主角在走路walk还是跳跃jump,都会变成闲置idle状态。其他同理。

接下来一个重点是callbacks参数,

即所谓回调了,就是事件触发,会执行一系列的函数。

  • onbeforeEVNET: 在事件EVENT开始前被激活
  • onleaveSTATE: 在离开旧状态STATE时被激活
  • onenterSTATE 或 onSTATE:在进入新状态STATE时被激活
  • onafterEVENT 或 onEVENT:在事件EVENT结束后被激活

例如

callbacks = {
	onenteridle = function ()  --或者 onidle
		print("idle")
	end,
},

此外还有5种通用型的回调来捕获所有事件和状态的变化:

  • onbeforeevent: 在任何事件开始前被激活
  • onleavestate: 在离开任何状态时被激活
  • onenterstate:在进入任何状态时被激活
  • onafterevent :在任何事件结束后被激活
  • onchangestate :当状态发生改变的时候被激活

这里面的名称是不可以修改的,它是针对于任何事件和任何状态的。

所以大家可以想象一下这其中有多少事件回调和多少状态回调,它们的先后顺序,咱们可以自己分别print一下就知道调用的先后了,这里就不演示了。

最后,就是调用这些事件了,通过self.fsm:doEvent(event)就可以了,参数event对应events参数名称。此外还有这些,

  • fsm:isReady() :返回状态机是否就绪
  • fsm:getState() :返回当前状态
  • fsm:isState(state) :判断当前状态是否是参数state状态
  • fsm:canDoEvent(eventName) :当前状态如果能完成eventName对应的event的状态转换,则返回true
  • fsm:cannotDoEvent(eventName) :当前状态如果不能完成eventName对应的event的状态转换,则返回true
  • fsm:isFinishedState() :当前状态如果是最终状态,则返回true
  • fsm:doEventForce(name, ...) :强制对当前状态进行转换

接下来在实际运用一下,我们创建一个Player类,为其添加一个状态机,

local Player = class("Player", function ()
	return display.newSprite("icon.png")
end)

function Player:ctor()
	self:addStateMachine()
end

function Player:doEvent(event)
	self.fsm:doEvent(event)
end

function Player:addStateMachine()
	self.fsm = {}
	cc.GameObject.extend(self.fsm):addComponent("components.behavior.StateMachine"):exportMethods()

	self.fsm:setupState({
		initial = "idle",

		events = {
			{name = "move", from = {"idle", "jump"}, to = "walk"},
			{name = "attack", from = {"idle", "walk"}, to = "jump"},
			{name = "normal", from = {"walk", "jump"}, to = "idle"},
		},

		callbacks = {
			onenteridle = function ()
				local scale = CCScaleBy:create(0.2, 1.2)
				self:runAction(CCRepeat:create(transition.sequence({scale, scale:reverse()}), 2))
			end,

			onenterwalk = function ()
				local move = CCMoveBy:create(0.2, ccp(100, 0))
				self:runAction(CCRepeat:create(transition.sequence({move, move:reverse()}), 2))
			end,

			onenterjump = function ()
				local jump = CCJumpBy:create(0.5, ccp(0, 0), 100, 2)
				self:runAction(jump)
			end,
		},
	})
end

return Player

比较简单,回调函数只是写了进入三个状态的回调,然后为Player添加一个doEvent函数,调用状态机中doEvent。

回到我们的MyScene.lua中,

local Player = import("..views.Player")

local MyScene = class("MyScene", function ()
	return display.newScene("MyScene")
end)

function MyScene:ctor()	

    local player = Player.new()
    player:setPosition(display.cx, display.cy)
    self:addChild(player)

    local function menuCallback(tag)
        if tag == 1 then
            player:doEvent("normal")
        elseif tag == 2 then
            player:doEvent("move")
        elseif tag == 3 then
            player:doEvent("attack")
        end
    end

    local mormalItem = ui.newTTFLabelMenuItem({text = "normal", x = display.width*0.3, y = display.height*0.2, listener = menuCallback, tag = 1})
    local moveItem =  ui.newTTFLabelMenuItem({text = "move", x = display.width*0.5, y = display.height*0.2, listener = menuCallback, tag = 2})
    local attackItem =  ui.newTTFLabelMenuItem({text = "attack", x = display.width*0.7, y = display.height*0.2, listener = menuCallback, tag = 3})
    local menu = ui.newMenu({mormalItem, moveItem, attackItem})
    self:addChild(menu)

end

return MyScene

添加我们刚才的Player,记得import或者require,这里为了方便我就通过菜单按钮的形式来分别doEvent了。

点击打开链接

时间: 2024-10-08 15:20:47

Quick StateMachine状态机的相关文章

quick StateMachine 状态机的使用

quick 的状态机 真是使用简单,功能强大,记录一下使用方式便于以后使用 1:创建一个状态机StateMachine (1) self.fsm_ = StateMachine.new() (2)self:addComponent("component.behavior.StateMachine") self.fsm_ = self:getComponent("component.behavior.StateMachine") 2:setupState self.f

quick-cocos2d-x游戏开发【14】——StateMachine状态机

状态机在quick中是一个亮点,如果我们做一款RPG游戏,一个角色一般会拥有idle,attack,walk,run,death这些状态,如果游戏角色的状态采用分支条件判断的话,会造成非常庞大而难以维护,但一旦使用了状态机这种模式,就会显得简单方便. 对于quick中的状态机是如何实现的咱们先不去了解,首先看看如何去使用它. 总结起来,如果让一个类拥有状态机,主要有两步: 1.创建状态机对象 2.初始化状态机,主要包括事件和回调函数 1.创建状态机组件 self.fsm = {} cc.Game

Qt Qml状态机框架

Qt5.4引入了QML状态机框架,与C++状态机框架类似,可以在应用程序中创建并执行状态图.为此,QtQml.StateMachine模块提供了一些相关的QML类型,用于创建事件驱动的状态机,这些QML类型列举如下: StateMachine-- 状态机管家,执行算法基于SCXML(State Chart XML),在状态机启动之前要设置好初始状态,即initialState属性. State--状态机中的通用类型,注意与QtQuick模块中的State类型不同,导入模块时先导入QtQuick模

mina statemachine解读(一)

  statemachine(状态机)在维护多状态数据时有非常好的作用,现在github上star排名最前的是squirrel-foundation以及spring-statemachine,而mina的statemachine好像并没有对外提供,多用于mina的高级特性里面. 了解了下spring-statemachine,提供特别完善的扩展方式,interceptor,listener,甚至支持分布式,但是上手使用还是有一定的难度,代码也比较复杂,状态机的实例比较重.没有看到较好的现实应用实

Android4.4(MT8685)源码WIFI--启动

系统启动时,会在SystemServer中创建一个WifiService的对象,并把这个对象保存在系统服务中 wifi = new WifiService(context); ServiceManager.addService(Context.WIFI_SERVICE, wifi); 看看WiFiService的构造方法 public WifiService(Context context) { mContext = context; mInterfaceName = SystemPropert

Android 4.2 Bluetooth 分析总结(二) 蓝牙enable 的整个过程

转载请标明出处:Android 4.2 Bluetooth 分析总结(二) 蓝牙enable 的整个过程 现在开始我们分析 Android4.2 Bluetooth 打开的整个过程,由于是新手,难免有很多错误,记录只是为了以后方便查找,如发错误敬请指出. 我们整个分析过程有可能有点繁琐,但请仔细阅读,读完之后必然发现还是会有一点点收获的,虽然写的不好.搜先我们上一份enable 打开蓝牙整个过程的打印:然后我们跟踪打印来窥探 Android4.2Bluetooth 工作的流程. D/Blueto

Android与设计模式——状态(State)模式

在阎宏博士的<JAVA与模式>一书中开头是这样描述状态(State)模式的: 状态模式,又称状态对象模式(Pattern of Objects for States),状态模式是对象的行为模式. 状态模式允许一个对象在其内部状态改变的时候改变其行为.这个对象看上去就像是改变了它的类一样. 状态模式的结构 用一句话来表述,状态模式把所研究的对象的行为包装在不同的状态对象里,每一个状态对象都属于一个抽象状态类的一个子类.状态模式的意图是让一个对象在其内部状态改变的时候,其行为也随之改变.状态模式的

转 springboot 教程

转 Spring Boot 揭秘与实战 系列 发表于 2016-12-21 | Spring框架 | SpringBoot 文章目录 1. 快速上手篇 2. 数据存储篇 3. 数据缓存篇 4. 日志框架篇 5. 配置文件篇 6. 服务器篇 7. 消息队列篇 8. 实用技术篇 9. 发布与部署 10. 应用监控篇 11. 源码分析篇 12. 附录 13. 源代码 <Spring Boot 揭秘与实战>系列,汇总文集. 快速上手篇 Spring Boot 揭秘与实战(一) 快速上手 数据存储篇 S

(六)Unity5.0新特性------新动画功能

?? unity 5.0 中的新动画功能 这里是你可以期待的新动画功能快速概述 ! State Machine Behaviours状态机行为 在Unity 5 中,你会能够将StateMachineBehaviour 脚本添加到您的states,当played状态时能接收callbacks回调: ?OnStateEnter ?OnStateUpdate ?OnStateExit ?OnStateMove ?OnStateIK 在你的状态,您可以创建尽可能多的StateMachineBehavi