Lua StateMachine状态机 记录

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

  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 :当状态发生改变的时候被激活

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

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

   还有如下api方法:

  • 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

转载于:https://my.oschina.net/u/223340/blog/323464

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值