State machine in Quick is a bright spot, if we do an RPG game, a role will generally have idle,attack,walk,run,death these states, if the role of the game is determined by the condition of the branch conditions, it will cause very large and difficult to maintain, But once the state machine is used this mode, it will appear simple and convenient.
For how the state machine in quick is implemented, let's first look at how to use it.
To sum up, if a class has a state machine, there are two main steps:
1. Create a state machine object
2. Initialize the state machine, mainly including events and callback functions
1. Create the Status Unit components
SELF.FSM = {}cc. Gameobject.extend (SELF.FSM): AddComponent ("Components.behavior.StateMachine"): Exportmethods ()
this creates a state machine object, and then we initialize it, which is the logic that sets each state.
2. Initialize the state machine (set state logic)
Setting the state logic is overriding the Setupstate method, which has so many field parameters,
- Initial: Initial state of the state machine
- Terminal (final): End state
- Events: The corresponding event when the state changes
- Callbacks: Callback function when a transition occurs
Generally we will set initial,events and callbacks these three.
In events, we need to be clear about "event" and "state" in events, which uses the table structure, for example, we write a
Events = { {name = ' move ', from = {' Idle ', ' jump '}, to = ' Walk '},}
This move is an event, just like Touch event Event.name, where name represents the event name, and the Idle,jump,walk that follows from and to represents the state. So the above means that when the move event is executed, if the state is idle or jump, it jumps to the walk state.
From the state can be a single state, you can also make the collection state, is a few states, but to the state can only be unique, or the program will give you a random state? Definitely not.
So here we need to figure out what the status of our protagonist is, and when what happens, he will change from what state to what state. For example, I wrote it so easily,
Events = {{name = ' move ', from = {' Idle ', ' jump '}, to = ' walk '},{name = ' attack ', from = {' Idle ', ' walk '}, to = ' Jump '},{n ame = ' normal ', from = {' Walk ', ' jump '}, to = ' idle '},
explain that if the normal event, whether the protagonist is walking walk or jumping jump, will become idle idle state. The other same.
The next focus is on the callbacks parameter,
The so-called callback, which is the event trigger, executes a series of functions.
- Onbeforeevnet: Activated before event events start
- Onleavestate: Activated when leaving the old state
- Onenterstate or onstate: Activated when entering new state
- Onafterevent or OnEVENT: Activated at the end of events event
For example
Callbacks = {Onenteridle = function () --or Onidleprint ("idle") End,},
There are also 5 general-purpose callbacks to capture changes in all events and states:
- Onbeforeevent: Activated before any event starts
- Onleavestate: Activated when left in any state
- Onenterstate: Activated when entering any state
- Onafterevent: Activated at the end of any event
- Onchangestate: Activated when a change of state occurs
The name in this is not modifiable, it is for any event and any state. So you can imagine how many of these event callbacks and how many state callbacks, their order, we can separate print to know the number of calls, here is not a demonstration.
Finally, these events are invoked by Self.fsm:doEvent (event), and the event parameter corresponds to the events parameter name. There are also these,
- Fsm:isready (): Returns whether the state machine is ready
- Fsm:getstate (): Returns the current state
- Fsm:isstate (state): Determines whether the current status is a parameter state status
- Fsm:candoevent (EventName): Returns True if the current state can complete the state transition of the eventName corresponding event
- Fsm:cannotdoevent (eventName): The current state returns true if the state transition of the corresponding event cannot be completed EventName
- Fsm:isfinishedstate (): Returns True if the current state is the final state
- Fsm:doeventforce (Name, ...): Forces a transition to the current state
And then in practical use, we create a player class, add a state machine to it,
Local Player = Class ("Player", function () return Display.newsprite ("Icon.png") end) function Player:ctor () Self: Addstatemachine () endfunction player:doevent (event) self.fsm:doEvent (event) endfunction 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", the From = {"id Le ', ' 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 (0)) Self:runaction (Ccrepeat:create ( Transition.sequence ({move, Move:reverse ()}), 2)) End,onenterjump = function () Local jump = ccjumpby:create (0.5, CCP (0, 0) , 2) self:runaction (jump) End,},}) Endreturn Player
Relatively simple, the callback function simply writes a callback into three states and then adds a doevent function to the player, calling Doevent in the state machine.
Back in our Myscene.lua,
Local Player = Import (".. Views. Player ") Local MyScene = Class (" MyScene ", function () return Display.newscene (" MyScene ") end) function Myscene:ctor () loc Al player = Player.new () player:setposition (display.cx, display.cy) self:addchild (player) local function Menucall Back (tag) if tag = = 1 then player:doevent ("normal") elseif tag = = 2 Then Player:doeve NT ("move") elseif tag = = 3 then player:doevent ("attack") end end Local Mormalitem = UI.NEWT Tflabelmenuitem ({text = "normal", x = display.width*0.3, y = display.height*0.2, listener = menucallback, tag = 1}) loc Al MoveItem = Ui.newttflabelmenuitem ({text = "move", x = display.width*0.5, y = display.height*0.2, listener = Menucallba CK, 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) Endreturn MyScene
Add our earlier player, remember import or require, here for the convenience of me through the form of menu buttons to doevent respectively.
Click to open link
Quick StateMachine State Machine