• Lua FSM有限状态机的实现


    最近做项目,因为要将游戏的代码基本全部改成lua的,对c#层面的东西基本只要unity的生命周期就可以了。刚开始接触lua,心痒痒,决定上网买了《Lua游戏AI开发指南》看看,决定实现一个fsm以便于在项目中使用。在这里贴出代码,其实代码都是直接抄这本书的。建议直接买书看,对于不想买书又想实现lua的状态机的可以直接拿下面的代码使用就可以了。

     1 Action = {}
     2 
     3 Action.Status = {
     4     RUNNING = "RUNNING",
     5     TERMINATED = "TERMINATED",
     6     UNINIIALIZED = "UNINIIALIZED"
     7 }
     8 
     9 Action.Type = "Action"
    10 
    11 
    12 function Action.new(name,initializeFunction,updateFunction,cleanUpFunction,userData)
    13 
    14     local action = {}
    15 
    16     action.cleanUpFunction_ = cleanUpFunction
    17     action.initializeFunction_ = initializeFunction
    18     action.updateFunction_  = updateFunction
    19     action.name_ = name or ""
    20     action.status_ = Action.Status.UNINIIALIZED
    21     action.type_ = Action.Type
    22     action.userData_ = userData
    23 
    24     action.CleanUp = Action.CleanUp
    25     action.Initialize = Action.Initialize
    26     action.Update = Action.Update
    27 
    28     return action
    29 end
    30 
    31 function Action.Initialize(self)
    32     if self.status_ == Action.Status.UNINIIALIZED then
    33         if self.initializeFunction_ then
    34             self.initializeFunction_(self.userData_)
    35         end
    36     end
    37 
    38     self.status_ = Action.Status.RUNNING
    39 end
    40 
    41 
    42 function Action.Update(self,deltaTimeInMillis)
    43     if self.status_ == Action.Status.TERMINATED then
    44         return Action.Status.TERMINATED
    45     elseif self.status_ == Action.Status.RUNNING then
    46         if self.updateFunction_ then
    47             self.status_ = self.updateFunction_(deltaTimeInMillis,self.userData_)
    48 
    49             assert(self.status_)
    50         else
    51             self.status_ = Action.Status.TERMINATED
    52         end
    53     end
    54 
    55     return self.status_
    56 
    57 end
    58 function Action.CleanUp(self)
    59     if self.status_ == Action.Status.TERMINATED then
    60         if self.cleanUpFunction_ then
    61             self.cleanUpFunction_(self.userData_)
    62         end
    63     end
    64 
    65     self.status_ = Action.Status.UNINIIALIZED
    66 end
    Action
     1 require "Action"
     2 --require "FiniteState"
     3 require "FiniteStateTransition"
     4 
     5 FiniteState = {}
     6 
     7 function FiniteState.new(name,action)
     8     local state = {}
     9     -- 状态的数据
    10     state.name_ = name
    11     state.action_ = action
    12 
    13     return state
    14 end
    FiniteState
     1 FiniteStateTransition = {}
     2 
     3 function FiniteStateTransition.new(toStateName,evaluator)
     4     local transition = {}
     5 
     6     -- 状态转换条件的数据
     7     transition.evaluator_ = evaluator
     8     transition.toStateName_ = toStateName
     9 
    10     return transition
    11 end
    FiniteStateTransition
      1 require "Action"
      2 require "FiniteState"
      3 require "FiniteStateTransition"
      4 
      5 FiniteStateMachine = {}
      6 
      7 function FiniteStateMachine.new(userData)
      8     local fsm = {}
      9 
     10     -- 状态机的数据
     11     fsm.currentState_ = nil
     12     fsm.states_ = {}
     13     fsm.transition_ = {}
     14     fsm.userData_ = userData
     15 
     16     fsm.AddState = FiniteStateMachine.AddState
     17     fsm.AddTransition = FiniteStateMachine.AddTransition
     18     fsm.ContainState = FiniteStateMachine.ContainState
     19     fsm.ContainTransition = FiniteStateMachine.ContainTransition
     20     fsm.GetCurrentStateName = FiniteStateMachine.GetCurrentStateName
     21     fsm.GetCurrentStateStatus = FiniteStateMachine.GetCurrentStateStatus
     22     fsm.SetState = FiniteStateMachine.SetState
     23     fsm.Update = FiniteStateMachine.Update
     24 
     25     return fsm
     26 end
     27 
     28 
     29 function FiniteStateMachine.ContainState(self,stateName)
     30     return self.states_[stateName] ~= nil
     31 end
     32 
     33 function FiniteStateMachine.ContainTransition(self,fromStateName,toStateName)
     34     return self.transition_[fromStateName] ~= nil and
     35         self.transition_[fromStateName][toStateName] ~= nil
     36 end
     37 
     38 function FiniteStateMachine.GetCurrentStateName(self)
     39     if self.currentState_ then
     40         return self.currentState_.name_
     41     end
     42 end
     43 
     44 function FiniteStateMachine.GetCurrentStateStatus(self)
     45     if self.currentState_ then
     46         return self.currentState_.action_.status_
     47     end
     48 end
     49 
     50 
     51 function FiniteStateMachine.SetState(self,stateName)
     52     if self:ContainState(stateName) then
     53         if self.currentState_ then
     54             self.currentState_.action_:CleanUp()
     55         end
     56 
     57         self.currentState_ = self.states_[stateName]
     58         self.currentState_.action_:Initialize()
     59     end
     60 end
     61 function FiniteStateMachine.AddState(self,name,action)
     62     self.states_[name] = FiniteState.new(name,action)
     63 end
     64 
     65 function FiniteStateMachine.AddTransition(self,fromStateName,toStateName,evaluator)
     66     if self:ContainState(fromStateName) and
     67         self:ContainState(toStateName) then
     68 
     69         if self.transition_[fromStateName] == nil then
     70             self.transition_[fromStateName] = {}
     71         end
     72 
     73         table.insert(
     74             self.transition_[fromStateName],
     75             FiniteStateTransition.new(toStateName,evaluator)
     76         )
     77 
     78     end
     79 end
     80 local function EvaluateTransitions(self,transitions)
     81     for index = 1 , #transitions do
     82         if transitions[index].evaluator_(self.userData_) then
     83             return transitions[index].toStateName_;
     84         end
     85     end
     86 end
     87 function FiniteStateMachine.Update(self,deltaTimeInMillis)
     88     if self.currentState_ then
     89         local status = self:GetCurrentStateStatus()
     90 
     91         if status == Action.Status.RUNNING then
     92             self.currentState_.action_:Update(deltaTimeInMillis)
     93         elseif status == Action.Status.TERMINATED then
     94             local toStateName = EvaluateTransitions(self,self.transition_[self.currentState_.name_])
     95 
     96             if self.states_[toStateName] ~= nil then
     97                 self.currentState_.action_:CleanUp()
     98                 self.currentState_ = self.states_[toStateName]
     99                 self.currentState_.action_:Initialize()
    100             end
    101         end
    102     end
    103 end
    FiniteStateMachine

    下面是测试代码

     1 timer = 0
     2 
     3 function SoldierActions_IdleCleanUp(userData)
     4     print("SoldierActions_IdleCleanUp data is "..userData)
     5     timer = 0
     6 end
     7 
     8 function SoldierActions_IdleInitialize(userData)
     9     print("SoldierActions_IdleInitialize data is "..userData)
    10     timer = 0
    11 end
    12 
    13 function SoldierActions_IdleUpdate(deltaTimeInMillis,userData)
    14     print("SoldierActions_IdleUpdate data is "..userData)
    15     timer = (timer + 1)
    16     if timer > 3 then
    17         return Action.Status.TERMINATED
    18     end
    19 
    20     return Action.Status.RUNNING
    21 end
    22 
    23 
    24 function SoldierActions_DieCleanUp(userData)
    25     print("SoldierActions_DieCleanUp data is "..userData)
    26     timer = 0
    27 end
    28 
    29 function SoldierActions_DieInitialize(userData)
    30     print("SoldierActions_DieInitialize data is "..userData)
    31     timer = 0
    32 end
    33 
    34 function SoldierActions_DieUpdate(deltaTimeInMillis,userData)
    35     print("SoldierActions_DieUpdate data is "..userData)
    36     timer = (timer + 1)
    37     if timer > 3 then
    38         return Action.Status.TERMINATED
    39     end
    40 
    41     return Action.Status.RUNNING
    42 end
    SoldierActions
    1 function SoldierEvaluators_True(userData)
    2     print("SoldierEvaluators_True data is "..userData)
    3     return true
    4 end
    5 
    6 function SoldierEvaluators_False(userData)
    7     print("SoldierEvaluators_True data is "..userData)
    8     return false
    9 end
    SoldierEvaluators
     1 require "SoldierActions"
     2 require "FiniteStateMachine"
     3 require "SoldierEvaluators"
     4 
     5 local function IdleAction(userData)
     6     return Action.new(
     7         "idle",
     8         SoldierActions_IdleInitialize,
     9         SoldierActions_IdleUpdate,
    10         SoldierActions_IdleCleanUp,
    11         userData
    12     )
    13 end
    14 
    15 
    16 local function DieAction(userData)
    17     return Action.new(
    18         "die",
    19         SoldierActions_DieInitialize,
    20         SoldierActions_DieUpdate,
    21         SoldierActions_DieCleanUp,
    22         userData
    23     )
    24 end
    25 
    26 function SoldierLogic_FiniteStateMachine(userData)
    27     local fsm = FiniteStateMachine.new(userData)
    28     fsm:AddState("idle",IdleAction(userData))
    29     fsm:AddState("die",    DieAction(userData))
    30 
    31     fsm:AddTransition("idle","die",SoldierEvaluators_True)
    32     fsm:AddTransition("die","idle",SoldierEvaluators_True)
    33 
    34     fsm:SetState('idle')
    35 
    36     return fsm
    37 end
    SoldierLogic

    基本就是这样,挺喜欢这个状态机的。

    这本书还有讲决策树和行为树的代码,以后有需求再实现一遍。

  • 相关阅读:
    用户登陆显示cpu、负载、内存信息
    递归算法总结
    Java算法之递归打破及在真实项目中的使用实例
    史上最简单,一步集成侧滑(删除)菜单,高仿QQ、IOS。
    仿饿了么购物车下单效果
    一起来写个酷炫的水波纹浪啊浪界面
    一行实现QQ群组头像,微信群组,圆角等效果. 并支持url直接加载图片
    使用 CoordinatorLayout 实现复杂联动效果
    这交互炸了(三) :不看后悔!你一定没见过这样的闪屏
    这交互炸了(二):爱范儿是如何让详情页缩小为横向列表的
  • 原文地址:https://www.cnblogs.com/SeaSwallow/p/7118676.html
Copyright © 2020-2023  润新知