最近做项目,因为要将游戏的代码基本全部改成lua的,对c#层面的东西基本只要unity的生命周期就可以了。刚开始接触lua,心痒痒,决定上网买了《Lua游戏AI开发指南》看看,决定实现一个fsm以便于在项目中使用。在这里贴出代码,其实代码都是直接抄这本书的。建议直接买书看,对于不想买书又想实现lua的状态机的可以直接拿下面的代码使用就可以了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
下面是测试代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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
基本就是这样,挺喜欢这个状态机的。
这本书还有讲决策树和行为树的代码,以后有需求再实现一遍。