lua版本的一个状态机
这个状态机http://www.cnblogs.com/flytrace/p/5587033.html的lua版本
- -- LUA 有实现枚举值的好办法么
- local sc_enum =
- {
- -- event flow be broke up
- none = "none",
- -- event flow pass througth next state
- forward = "forward",
- -- deffer a speciafic event
- --deffer = 4
- -- select by default(the first position in the list)
- shallow = "shallow",
- -- the state will remain actived state that last time was
- deep = "deep",
- -- 不实现。该模式定义不良好。多个嵌套的子并行状态相对复杂,流程不清晰,数据结构也不直接。
- -- 还没找到比较良好的并行状态语义。
- -- only one substate can run at one time by default
- singleman = "singleman",
- -- the state will be enabled always, substate in parallel region can't transit to none-parallel region
- parallel = "parallel",
- }
- return sc_enum
- -- Date 2016-7-13
- -- yanfei
- --[[
- 一个sc_fsm也是一个sc_state,状态机本身也可以作为一个状态,但目前子状态机只能视为状态,未能作为独立的机制运行
- sc_fsm
- {
- type2states -- save all states accord to their name in a dictionary
- }
- --]]
- sc_helper = require("fsm.sc_helper")
- require("utils.sc_list")
- local sc_queue = require("utils.sc_queue")
- local sc_enum = require("fsm.sc_enum")
- local sc_state = require("fsm.sc_state")
- local classprototype = require("utils.middleclass")
- -- a fsm is a state
- local fsm = classprototype("sc_fsm", sc_state)
- -- 建立类型-状态表
- local function buildstates(fsm, astate)
- fsm.type2states[astate.statename] = astate
- if astate.substates then
- for statename_, state_ in ipairs(astate.substates) do
- assert(fsm.type2states[state_.statename] == nil, string.format("[%s]: has a state named [%s] already!", fsm.statename, state_.statename))
- buildstates(fsm, state_)
- end
- end
- end
- -- 重载initialize
- -- @statename_ 状态名字
- -- @basestate_ 父状态
- -- @statemode_ 运行模式
- -- @operation_ 激活操作
- function fsm:initialize(statename_, basestate_, statemode_, operation_)
- sc_state.initialize(self, statename_, basestate_, statemode_, operation_)
- end
- function fsm:init(initstatename)
- assert(type(self) == 'table', "Make sure that you are using 'fsm:init' instead of 'fsm.init'")
- self.type2states = {}
- buildstates(self, self)
- local initstate = self.type2states[initstatename]
- assert(initstate and initstate:isInstanceOf(sc_state), string.format("[%s] hasn't state named [%s]", self.statename, initstatename))
- -- 建立主激活列表
- local astate = initstate
- while astate do
- astate.activesubstate = astate.substates and astate.substates[] or nil
- self.ineststate = astate.activesubstate and astate.activesubstate or astate
- astate = astate.activesubstate
- end
- astate = initstate
- while astate ~= self do
- astate.basestate.activesubstate = astate
- astate = astate.basestate
- end
- astate = self
- while astate.activesubstate ~= nil do
- if astate.activesubstate.enter then astate.activesubstate:enter(self) end
- astate = astate.activesubstate
- end
- if not self.eventqueue then self.eventqueue = sc_queue:newqueue() end
- self.suspend = false
- self.__lockqueue = false
- self.__transiting = false
- return true
- end
- -- 跳转到目标状态
- function fsm:transit( targetname_ )
- assert(type(self) == 'table', "Make sure that you are using 'fsm:transit' instead of 'fsm.transit'")
- if self.__transiting then
- self.__transiting = false
- return sc_enum.none
- end
- self.__transiting = true;
- local targetstate = self.type2states[targetname_]
- assert(targetstate and targetstate:isInstanceOf(sc_state), string.format("[%s] hasn't state named [%s]", self.statename, targetname_))
- -- detect the whole active state list
- local astate = self.ineststate
- --
- local bstate = targetstate
- local dis = astate.depth - bstate.depth
- if dis < then
- bstate, astate = astate, targetstate
- end -- bstate is topper
- dis = math.abs(dis)
- for i = , dis do astate = astate.basestate end --now they are both same depth
- if astate == bstate then -- is family
- self.__transiting = false
- return sc_enum.none
- end
- -- find nearest ancestor both
- while astate ~= bstate do
- astate, bstate = astate.basestate, bstate.basestate
- end
- -- first we will call exit chain
- while self.ineststate ~= astate do
- if self.ineststate.exit then self.ineststate:exit(self) end
- self.ineststate = self.ineststate.basestate
- end
- -- now we will decide the enter chain
- -- build active chain down side
- local astate = targetstate
- while astate do
- astate.activesubstate = (astate.substates and astate.statemode == sc_enum.shallow)
- and astate.substates[] or astate.activesubstate
- self.ineststate = astate.activesubstate and astate.activesubstate or astate
- astate = astate.activesubstate
- end
- -- build active chain up side
- astate = targetstate
- while astate ~= self do
- astate.basestate.activesubstate, astate = astate, astate.basestate
- end
- -- call enter chain
- while bstate.activesubstate ~= nil do
- if bstate.activesubstate.enter then bstate.activesubstate:enter(self) end
- bstate = bstate.activesubstate
- end
- return sc_enum.none
- end
- function fsm:process_event( eventname_, ...)
- assert(type(self) == 'table', "Make sure that you are using 'fsm:process_event' instead of 'fsm.process_event'")
- if self.suspend then return nil end
- if self.__lockqueue then return nil end
- local pevent = {...}
- pevent.eventname = eventname_
- if not self.eventqueue then self.eventqueue = sc_queue:newqueue() end
- local queue = self.eventqueue
- queue:push_back(pevent)
- self.__lockqueue = true
- --local eventcount = queue:count()
- while true do
- --eventcount = eventcount - 1
- local astate = self
- local processflag_ = sc_enum.forward
- pevent = queue:pop_front()
- if not pevent then break end
- while astate.activesubstate ~= nil do
- processflag_ = astate.activesubstate:_internal_process(self, pevent)
- if processflag_ == sc_enum.none then
- return processflag_
- end
- astate = astate.activesubstate
- end
- end
- self.__lockqueue = false
- return processflag_
- end
- --
- function fsm:post_event( eventname_, ... )
- local pevent = {...}
- pevent.eventname = eventname_
- self.eventqueue:push_back(pevent)
- end
- function fsm:context( statename_ )
- local targetstate = self.type2states[targetname_]
- --assert(targetstate and targetstate:isInstanceOf(sc_state), string.format("[%s] hasn't state named [%s]", self.statename, targetname_))
- return targetstate
- end
- return fsm
- -- Date 2016-7-13
- -- yanfei
- --[[
- -- sc_state
- -- {
- statename, -- 状态名
- basestate, -- 父状态
- statemode, -- 历史模式
- operation, -- 操作,完成并行,筛选。目前保留字段
- substates, -- 子状态列表
- activestate, -- 当前激活状态
- events,, -- event-callback表
- -- }
- -- 一个状态是一个节点,basestate指向父状态,substates指向子状态列表,所有状态形成一棵树
- --]]
- require("utils.sc_list")
- local sc_enum = require("fsm.sc_enum")
- --require("fsm.sc_event")
- local classprototype = require("utils.middleclass")
- local sc_state = classprototype("sc_state")
- local rawget = rawget
- local rawset = rawset
- local string = string
- -- 重载initialize
- -- @statename_ 状态名字
- -- @basestate_ 父状态
- -- @statemode_ 运行模式
- -- @operation_ 激活操作
- function sc_state:initialize(statename_, basestate_, statemode_, operation_)
- assert(type(statename_) == "string","statename must be a string")
- self.statename = statename_
- self.statemode = statemode_ or sc_enum.shallow
- --self.operation = operation_ or sc_enum.singleman
- -- 处理父子关系
- assert(basestate_ and basestate_:isInstanceOf(sc_state) or basestate_ == nil, string.format("[%s]: base state must be a sc_state", statename_))
- self.basestate = basestate_
- if basestate_ then basestate_:addsubstate(self) end
- -- 状态深度 top state is 1
- self.depth = self.basestate and self.basestate.depth + or
- end
- -- 创建该状态的子状态
- function sc_state:createstate(statename_, statemode_, operation_)
- return sc_state:new(statename_, self, statemode_, operation_)
- end
- -- 添加子状态
- function sc_state:addsubstate(...)
- -- 填充子状态列表
- self.substates = self.substates or {}
- for i, state_ in ipairs{...} do
- assert(state_:isInstanceOf(sc_state), "substate must be a sc_state")
- assert(self.substates[state_.statename] == nil, string.format("%s has a substate named [%s] already!", self.statename, state_.statename))
- table.insert(self.substates, state_)
- end
- end
- -- 绑定事件
- -- @eventname_ 事件名
- -- @callbackname_ 事件处理函数名
- function sc_state:bind_event(eventname_, callbackname_)
- assert(type(self) == 'table', "Make sure that you are using 'sc_state:process_event' instead of 'sc_state.process_event'")
- assert(type(eventname_) == 'string', "Make sure that callbakname is a string")
- assert(type(callbackname_) == 'string', "Make sure that callbakname is a string")
- --local callback_ = self[callbackname_]
- local callback_ = rawget(self, callbackname_)
- assert(callback_, string.format("[%s] bind_event event[%s]: hasn't a function named [%s]", self.statename, eventname_, callbackname_))
- assert(type(callback_) == "function", string.format("[%s]:bind_event event[%s]: callback must be a function", self.statename, eventname_))
- self.events = self.events or {}
- self.events[eventname_] = function(fsm, ...) return callback_(self, fsm, ...) end
- end
- function sc_state:_internal_process(fsm, pevent)
- if not self.events then return sc_enum.forward end
- local callback_ = self.events[pevent.eventname]
- if not callback_ then return sc_enum.forward end
- return callback_(fsm, unpack(pevent))
- end
- return sc_state
- --region *.lua
- --Date 2016.7.17
- -- yanfei
- local queue = {}
- function queue:newqueue()
- local o = {first = , last = -}
- setmetatable(o, self)
- self.__index = self
- return o
- end
- function queue:push_front(v)
- local first = self.first -
- self.first = first
- self[first] = v
- end
- function queue:pop_front()
- local first = self.first
- if first > self.last then return nil end
- local v = self[first]
- self[first] = nil
- self.first = first +
- return v
- end
- function queue:push_back(v)
- local last = self.last +
- self.last = last
- self[last] = v
- end
- function queue:pop_back()
- local last = self.last
- if last < self.first then return nil end
- local v = self[last]
- self[last] = nil
- self.last = last -
- return v
- end
- function queue:count()
- return self.last - self.first +
- end
- return queue
- --endregion
- --region *.lua
- module ("sc_list", package.seeall)
- --- An iterator over the elements of a list.
- -- @param l list to iterate over
- -- @return iterator function which returns successive elements of the list
- -- @return the list <code>l</code> as above
- -- @return <code>true</code>
- function elems (l)
- local n =
- return function (l)
- n = n +
- if n <= #l then
- return l[n]
- end
- end,
- l, true
- end
- --- An iterator over the elements of a list, in reverse.
- -- @param l list to iterate over
- -- @return iterator function which returns precessive elements of the list
- -- @return the list <code>l</code> as above
- -- @return <code>true</code>
- function relems (l)
- local n = #l +
- return function (l)
- n = n -
- if n > then
- return l[n]
- end
- end,
- l, true
- end
- --- Fold a binary function into an iterator.
- -- @param f function
- -- @param d initial first argument
- -- @param i iterator
- -- @return result
- function fold_x (f, d, i, t)
- local r = d
- for e in i (t) do
- r = f (r, e)
- end
- return r
- end
- function fold (f, d, t)
- local r = d
- for e in elems (t) do
- r = f (r, e)
- end
- return r
- end
- ----- Fold a binary function through a list right associatively.
- ---- @param f function
- ---- @param e element to place in right-most position
- ---- @param l list
- ---- @return result
- --function foldr (f, e, l)
- -- return _G.fold (function (x, y) return f (y, x) end,
- -- e, relems, l)
- --end
- function find(f, t)
- for e in elems (t) do
- if f(e) then return e end
- end
- return nil
- end
- function findall(f, t)
- local result = {}
- for e in elems(t) do
- if f(e) then result[#result+] = (e) end
- end
- return result
- end
- function join(a, b)
- return {unpack(a), unpack(b)}
- end
- function cons(a, t)
- return {a, unpack(t)}
- end
- --endregion
使用
- -- 只是一个例子
- local sc_enum = require("fsm.sc_enum")
- local sc_fsm_pt = require("fsm.sc_fsm")
- local gamemain_fsm = sc_fsm_pt:new("gamemain_fsm")
- local print = print
- --[[
- -- gamemain_state
- --]]
- local gamemain_state = gamemain_fsm:createstate("gamemain_state")
- function gamemain_state:enter(fsm)
- print("enter "..self.statename)
- end
- function gamemain_state:exit(fsm)
- print("exit "..self.statename)
- end
- function gamemain_state:update(fsm, delta)
- print("update "..self.statename)
- print("timedelta: "..tostring(delta))
- end
- gamemain_state:bind_event("game_update", "update")
- --[[
- -- gamemain_init_state
- --]]
- local gamemain_init_state = gamemain_state:createstate("gamemain_init_state")
- function gamemain_init_state:enter(fsm)
- print("enter "..self.statename)
- end
- function gamemain_init_state:exit(fsm)
- print("exit "..self.statename)
- end
- --[[
- -- gamemain_init_waiting_state
- --]]
- local gamemain_init_waiting_state = gamemain_init_state:createstate("gamemain_init_waiting_state")
- function gamemain_init_waiting_state:enter(fsm)
- print("enter "..self.statename)
- end
- function gamemain_init_waiting_state:exit(fsm)
- print("exit "..self.statename)
- end
- --[[
- -- gamemain_idle_state
- --]]
- local gamemain_idle_state = gamemain_state:createstate("gamemain_idle_state")
- function gamemain_idle_state:enter(fsm)
- print("enter "..self.statename)
- end
- function gamemain_idle_state:exit(fsm)
- print("exit "..self.statename)
- end
- function gamemain_idle_state:update(fsm, delta)
- print("update "..self.statename)
- print("timedelta: "..tostring(delta))
- --fsm:process_event("game_upadte", 0.0001)
- end
- function gamemain_idle_state:tolobby(fsm, msg1, msg2)
- print(msg1..' '..msg2)
- print("ready to taransit to lobby")
- return fsm:transit("gamemain_lobby_state")
- end
- gamemain_idle_state:bind_event("game_update", "update")
- gamemain_idle_state:bind_event("event_tolobby", "tolobby")
- --[[
- -- gamemain_net_state
- --]]
- local gamemain_net_state = gamemain_state:createstate("gamemain_net_state")
- function gamemain_net_state:enter(fsm)
- print("enter "..self.statename)
- end
- function gamemain_net_state:exit(fsm)
- print("exit "..self.statename)
- end
- --[[
- -- gamemain_net_send_state
- --]]
- local gamemain_net_send_state = gamemain_net_state:createstate("gamemain_net_send_state")
- function gamemain_net_send_state:enter(fsm)
- print("enter "..self.statename)
- end
- function gamemain_net_send_state:exit(fsm)
- print("exit "..self.statename)
- end
- --[[
- -- gamemain_net_receive_state
- --]]
- local gamemain_net_receive_state = gamemain_net_state:createstate("gamemain_net_receive_state")
- function gamemain_net_receive_state:enter(fsm)
- print("enter "..self.statename)
- end
- function gamemain_net_receive_state:exit(fsm)
- print("exit "..self.statename)
- end
- --[[
- -- gamemain_lobby_state
- --]]
- local gamemain_lobby_state = gamemain_state:createstate("gamemain_lobby_state")
- function gamemain_lobby_state:enter(fsm)
- print("enter "..self.statename)
- end
- function gamemain_lobby_state:exit(fsm)
- print("exit "..self.statename)
- end
- --[[
- -- gamemain_lobby_shop_state
- --]]
- local gamemain_lobby_shop_state = gamemain_lobby_state:createstate("gamemain_lobby_shop_state")
- function gamemain_lobby_shop_state:enter(fsm)
- print("enter "..self.statename)
- fsm:post_event("event_opendoor", "opendoor")
- end
- function gamemain_lobby_shop_state:exit(fsm)
- print("exit "..self.statename)
- end
- function gamemain_lobby_shop_state:update(fsm, delta)
- print("update "..self.statename)
- print("timedelta: "..tostring(delta))
- end
- function gamemain_lobby_shop_state:opendoor(fsm)
- print("open the door")
- end
- gamemain_lobby_shop_state:bind_event("game_update", "update")
- gamemain_lobby_shop_state:bind_event("event_opendoor", "opendoor")
- --[[
- -- gamemain_lobby_dungeon_state
- --]]
- local gamemain_lobby_dungeon_state = gamemain_lobby_state:createstate("gamemain_lobby_dungeon_state")
- function gamemain_lobby_dungeon_state:enter(fsm)
- print("enter "..self.statename)
- end
- function gamemain_lobby_dungeon_state:exit(fsm)
- print("exit "..self.statename)
- end
- return gamemain_fsm
- --region *.lua
- --Date
- sc_helper = require("fsm.sc_helper")
- local sc_event = require("fsm.sc_event")
- local queue = require("utils.sc_queue")
- -- 获取定义好的gamemain状态机
- local gamemain_fsm = require("game.gamemain_fsm")
- -- 打印状态树
- sc_helper:printstates(gamemain_fsm)
- -- 初始化状态机,初始状态为gamemain_init_state,进入gamemain_init_state时将自动进入其子状态gamemain_init_waiting_state
- -- 进入某个状态后,如果有子状态,会尝试进入其子状态
- gamemain_fsm:init("gamemain_init_state")
- -- 自顶向下打印当前激活的状态链
- sc_helper:printactivestates(gamemain_fsm)
- -- 状态迁移到gamemain_idle_state
- gamemain_fsm:transit("gamemain_idle_state")
- sc_helper:printactivestates(gamemain_fsm)
- -- 发送事件game_update, 在gamemain_idle_state中注册了对该事件的响应
- gamemain_fsm:process_event("game_update", 0.0333333)
- -- 发送事件event_tolobby,在gamemain_idle_state中注册了对该事件的响应。在响应中将调用gamemain_fsm:transit迁移到gamemain_lobby_state
- gamemain_fsm:process_event("event_tolobby", "hello", "world")
- sc_helper:printactivestates(gamemain_fsm)
- gamemain_fsm:process_event("game_update", 0.0333333)
- print("over")
- --endregion
lua版本的一个状态机的更多相关文章
- 编译lua版本问题
Compile++ thumb : game_shared <= main.cppjni/hellocpp/main.cpp: In function 'void Java_org_cocos ...
- 5-(基础入门篇)学会刷Wi-Fi模块固件(刷LUA版本固件)
http://www.cnblogs.com/yangfengwu/p/9065559.html 基础教程源码链接请在淘宝介绍中下载,由于链接很容易失效,如果失效请联系卖家,谢谢 https://it ...
- 1-添加自己的Lua执行函数(ESP8266-SDK开发(lua版本))
基础 lua_pushnumber (L, 1); lua_pushnumber (L,3); lua_pushnumber (L,4); return 3; c_sprintf(temp, &quo ...
- Java Secret: Using an enum to build a State machine(Java秘术:用枚举构建一个状态机)
近期在读Hadoop#Yarn部分的源代码.读到状态机那一部分的时候,感到enmu的使用方法实在是太灵活了,在给并发编程网翻译一篇文章的时候,正好碰到一篇这种文章.就赶紧翻译下来,涨涨姿势. 原文链接 ...
- cocos2d-x3.0 lua学习(一个)
最近开始学习Lua这里记录下一个写简单Lua代码,但我在写Lua代码.自己主动的代码提示的一些问题,谁希望提供下很好的解决方案,编辑我用SubLime Text2 test.lua.这里创建一个场景, ...
- git 超前一个版本 落后一个版本的解决方案
在使用SourceTree的时候经常会遇见超前一个版本,落后N个版本的情况,遇见这种情况应该怎么办呢? 首先打开终端,最好是从SourceTree里面打开,菜单栏有个终端按钮. 然后输入: $ git ...
- xcode 运行 lua版本崩溃 解决方案
问题描述:运行到LuaStack::init() 崩溃 原因: luajit不支持arm64 解决方案:编译luajit64位静态库 a.可以直接下载别人编译好的库,然后直接覆盖cocos2d\ext ...
- 用openresty(Lua)写一个获取YouTube直播状态的接口
文章原发布于:https://www.chenxublog.com/2019/08/29/openresty-get-youtube-live-api.html 之前在QQ机器人上面加了个虚拟主播开播 ...
- [sqoop1.99.6] 基于1.99.6版本的一个小例子
1.创建mysql数据库.表.以及测试数据mysql> desc test;+-------+-------------+------+-----+---------+------------- ...
随机推荐
- Zabbix实战-简易教程--动作(Actions)--自动发现
一.概述 Zabbix提供了有效和非常灵活的网络自动发现功能. 设置网络发现后你可以: 加快Zabbix部署(自动添加主机.添加模板) 简化管理(自动删除主机.删除模板.禁用主机) 无需过多管理就能在 ...
- SSIS 延迟验证(DelayValidation)
验证是一个事件,该事件在Package执行时,第一个被触发,验证能够避免SSIS引擎执行一个有异常的Package或Task.延迟验证(DelayValidation)是把验证操作延迟到Package ...
- c#中常用集合类和集合接口之接口系列【转】
常用集合接口系列:http://www.cnblogs.com/fengxiaojiu/p/7997704.html 常用集合类系列:http://www.cnblogs.com/fengxiaoji ...
- IntelliJ IDEA 17和Maven构建javaWeb项目
前言 电脑又断电了,眼看着写好的东西就没有了,这是第二次犯这个错误了.很难受呀!还是回到正题吧,我们来使用IDEA和Maven构建一个JavaWeb项目 软件环境: IDEA:2017.2.1 JDK ...
- POJ2689-Prime Distance-区间筛素数
最近改自己的错误代码改到要上天,心累. 这是迄今为止写的最心累的博客. Prime Distance Time Limit: 1000MS Memory Limit: 65536K Total S ...
- 简单的面向对象(OO)练习
学生设备管理系统: 每个学校都有很多班级,每个班级都有很多设备.(设备可以更新)每个设备都有购买价格,每种设备都有折旧率(如每年折旧10%) 按班级进行统计,指定的班级有多少的设数量? 按班级进行统计 ...
- js代码性能优化的几个方法
相信写代码对于大部分人都不难,但想写出高性能的代码就需要一定的技术积累啦,下面是一些优化JavaScript代码性能的常见方法. 一.注意作用域 1.避免全局查找 使用全局变量和函数肯定要比局部的开销 ...
- radiobutton独特属性
radiobutton是通过name来分组的,也就是说,使用相同的名字的radio,它们才是单选的,如果名字不同的radio,是不具备这个效果的,这个是第一要点. 第二,针对不同的radio(name ...
- MLlib--PIC算法
转载请标明出处http://www.cnblogs.com/haozhengfei/p/82c3ef86303321055eb10f7e100eb84b.html PIC算法 幂迭代聚类 ...
- php常用数据结构
# 常用数据结构--------------------------------------------------------------------------------## 树(Tree)- ...