quick-cocos2d-x游戏开发14——StateMachine状态机
Posted wangdi1224
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了quick-cocos2d-x游戏开发14——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 :当状态发生改变的时候被激活
最后,就是调用这些事件了,通过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了。
以上是关于quick-cocos2d-x游戏开发14——StateMachine状态机的主要内容,如果未能解决你的问题,请参考以下文章