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

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

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

原文地址:https://www.cnblogs.com/SeaSwallow/p/7118676.html