• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

unindented/lua-fsm: A simple finite-state machine implementation for Lua.

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

unindented/lua-fsm

开源软件地址(OpenSource Url):

https://github.com/unindented/lua-fsm

开源编程语言(OpenSource Language):

Lua 99.4%

开源软件介绍(OpenSource Introduction):

lua-fsm Version Build Status Coverage Status

A simple finite-state machine implementation for Lua. Based on @jakesgordon's javascript-finite-state-machine.

Installation

You can install through LuaRocks:

$ luarocks install fsm

Or just download manually:

$ wget https://github.com/unindented/lua-fsm/raw/master/src/fsm.lua

Usage

Initialization

You can create a new state machine by doing something like:

local fsm = require "fsm"

local alert = fsm.create({
  initial = "green",
  events = {
    {name = "warn",  from = "green",  to = "yellow"},
    {name = "panic", from = "yellow", to = "red"   },
    {name = "calm",  from = "red",    to = "yellow"},
    {name = "clear", from = "yellow", to = "green" }
  }
})

This will create an object with a method for each event:

  • alert.warn() - causes the machine to transition from green to yellow
  • alert.panic() - causes the machine to transition from yellow to red
  • alert.calm() - causes the machine to transition from red to yellow
  • alert.clear() - causes the machine to transition from yellow to green

along with the following:

  • alert.current - contains the current state
  • alert.is(s) - returns true if state s is the current state
  • alert.can(e) - returns true if event e can be fired in the current state
  • alert.cannot(e) - returns true if event e cannot be fired in the current state
  • alert.transitions() - returns the list of events that are allowed from the current state

If you don't specify any initial state, the state machine will be in the none state, and you would need to provide an event to take it out of this state:

local alert = fsm.create({
  events = {
    {name = "startup", from = "none",  to = "green"},
    {name = "panic",   from = "green", to = "red"  },
    {name = "calm",    from = "red",   to = "green"}
  }
})

print(alert.current) -- "none"
alert.startup()
print(alert.current) -- "green"

If you specify the name of your initial state, then an implicit startup event will be created for you and fired when the state machine is constructed:

local alert = fsm.create({
  initial = "green",
  events = {
    {name = "panic", from = "green", to = "red"  },
    {name = "calm",  from = "red",   to = "green"}
  }
})

print(alert.current) -- "green"

If your object already has a startup method you can use a different name for the initial event:

local alert = fsm.create({
  initial = {state = "green", event = "init"},
  events = {
    {name = "panic", from = "green", to = "red"  },
    {name = "calm",  from = "red",   to = "green"}
  }
})

print(alert.current) -- "green"

Finally, if you want to wait to call the initial state transition event until a later date you can defer it:

local alert = fsm.create({
  initial = {state = "green", event = "init", defer = true},
  events = {
    {name = "panic", from = "green", to = "red"  },
    {name = "calm",  from = "red",   to = "green"}
  }
})

print(alert.current) -- "none"
alert.init()
print(alert.current) -- "green"

Callbacks

Four types of callback are available by attaching methods to your state machine, using the following naming conventions (where <EVENT> and <STATE> get replaced with your different event and state names):

  • on_before_<EVENT> - fired before the event
  • on_leave_<STATE> - fired when leaving the old state
  • on_enter_<STATE> - fired when entering the new state
  • on_after_<EVENT> - fired after the event

For convenience, the 2 most useful callbacks can be shortened:

  • on_<EVENT> - convenience shorthand for on_after_<EVENT>
  • on_<STATE> - convenience shorthand for on_enter_<STATE>

In addition, four general-purpose callbacks can be used to capture all event and state changes:

  • on_before_event - fired before any event
  • on_leave_state - fired when leaving any state
  • on_enter_state - fired when entering any state
  • on_after_event - fired after any event

All callbacks will be passed the same arguments:

  • self (the finite-state machine that generated the transition)
  • event name
  • from state
  • to state
  • (followed by any arguments you passed into the original event method)

Callbacks can be specified when the state machine is first created:

local fsm = require "fsm"

local alert = fsm.create({
  initial = "green",
  events = {
    {name = "warn",  from = "green",  to = "yellow"},
    {name = "panic", from = "yellow", to = "red"   },
    {name = "calm",  from = "red",    to = "yellow"},
    {name = "clear", from = "yellow", to = "green" }
  },
  callbacks = {
    on_panic = function(self, event, from, to, msg) print('panic! ' .. msg)  end,
    on_clear = function(self, event, from, to, msg) print('phew... ' .. msg) end
  }
})

alert.warn()
alert.panic('killer bees')
alert.calm()
alert.clear('they are gone now')

The order in which callbacks occur is as follows, assuming event calm transitions from red state to yellow:

  • on_before_calm - specific handler for the calm event only
  • on_before_event - generic handler for all events
  • on_leave_red - specific handler for the red state only
  • on_leave_state - generic handler for all states
  • on_enter_yellow - specific handler for the yellow state only
  • on_enter_state - generic handler for all states
  • on_after_calm - specific handler for the calm event only
  • on_after_event - generic handler for all events

Deferred state transitions

You may need to execute additional code during a state transition, and ensure the new state is not entered until your code has completed, e.g. fading a menu screen.

One way to do this is to return fsm.DEFERRED from your on_leave_state handler, and the state machine will be put on hold until you are ready to confirm the transition by calling the confirm method, or cancel it by calling the cancel method:

local screens = fsm.create({
  initial = "menu",
  events = {
    {name = "play", from = "menu", to = "game"},
    {name = "quit", from = "game", to = "menu"}
  },
  callbacks = {
    on_leave_menu = function (self)
      fade_out(0.5, self.confirm)
      return fsm.DEFERRED
    end
  }
})

screens.play()

Meta

Contributors

License

Copyright (c) 2016 Daniel Perez Alvarez (unindented.org). This is free software, and may be redistributed under the terms specified in the LICENSE file.




鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap