lua實作的 FSM(finite-state machine)
代碼實作
為方便閱讀,只粘了核心代碼,完整版可移步Github:Lua_FSM - SouthBegonia
狀態基類 BaseFSMState.lua
---@class BaseFSMState FSM狀態基類
---@field public stateName string @狀態名
---@field private entryCondition function @進入此狀態的條件
BaseFSMState = {}
BaseFSMState.__index = BaseFSMState;
---實體化狀態
---@public
---@param stateName string
function BaseFSMState.New(stateName)
---@type BaseFSMState
local fsmState = setmetatable({}, BaseFSMState);
fsmState.stateName = stateName;
fsmState.entryCondition = nil;
return fsmState;
end
---設定 進入此狀態的條件
---@public
---@param condition function
function BaseFSMState:SetEntryCondition(condition)
self.entryCondition = condition;
end
---判斷 是否滿足進入此狀態的條件
---@public
---@return boolean
function BaseFSMState:CheckEntryCondition()
if (self.entryCondition ~= nil) then
return self.entryCondition();
end
return true;
end
---進入狀態
---@public
function BaseFSMState:OnEnter()
end
---更新狀態
---@public
function BaseFSMState:OnUpdate()
end
---離開狀態
---@public
function BaseFSMState:OnLeave()
end
狀態機基類 BaseFSM.lua
---@class BaseFSM FSM基類
---@field private states table<string, BaseFSMState> @持有的狀態 的表(key=BaseFSM.stateName value=https://www.cnblogs.com/SouthBegonia/archive/2022/11/19/BaseFSMState)
---@field private previousState BaseFSMState @先前狀態
---@field private currentState BaseFSMState @當前狀態
BaseFSM = {};
BaseFSM.__index = BaseFSM;
---構造 狀態機實體
---@public
---@return BaseFSM
function BaseFSM.New()
---@type BaseFSM
local fsm = setmetatable({}, BaseFSM);
fsm.states = {};
fsm.previousState = nil;
fsm.currentState = nil;
return fsm;
end
---添加 狀態
---@param fsmState BaseFSMState
---@return boolean @是否 成功添加狀態
function BaseFSM:AddState(fsmState)
if (fsmState == nil) then
--Error
return false;
end
if (self.states[fsmState.stateName] ~= nil) then
--Error
return false;
end
self.states[fsmState.stateName] = fsmState;
return true;
end
---設定 初始狀態
---@param fsmStateName string
function BaseFSM:SetStartState(fsmStateName)
local startFSMState = self.states[fsmStateName];
if (startFSMState == nil) then
--Error
return false;
end
self.previousState = nil;
self.currentState = startFSMState;
self.currentState:OnEnter();
return true;
end
---獲取 當前狀態
---@public
---@return BaseFSMState
function BaseFSM:GetCurrentState()
return self.currentState;
end
---切換到 目標狀態
---@public
---@param fsmStateName string
---@return boolean
function BaseFSM:ChangeState(fsmStateName)
---@type BaseFSMState
local targetFSMState = self.states[fsmStateName];
if (targetFSMState == nil) then
--Error
return false;
end
if (self.currentState == targetFSMState) then
--Error
return false;
end
if (not targetFSMState:CheckEntryCondition()) then
--Log
return false;
end
self.currentState:OnLeave();
self.previousState = self.currentState;
self.currentState = targetFSMState;
self.currentState:OnEnter();
return true;
end
---@public
function BaseFSM:Update()
if (self.currentState ~= nil) then
self.currentState:OnUpdate();
end
end
測驗:
---------- 添加 場景狀態列舉 ----------
local SceneFSMStateDefine = {
Login = "Login",
Home = "Home",
Battle = "Battle",
}
---------- 實體化 各場景狀態 ----------
---@type BaseFSMState
local sceneLoginFSMState = BaseFSMState.New(SceneFSMStateDefine.Login);
sceneLoginFSMState.OnEnter = function()
print("進入 Login狀態");
end
sceneLoginFSMState.OnLeave = function()
print("退出 Login狀態");
end
---@type BaseFSMState
local sceneHomeFSMState = BaseFSMState.New(SceneFSMStateDefine.Home);
sceneHomeFSMState.OnEnter = function()
print("進入 Home狀態");
end
sceneHomeFSMState.OnLeave = function()
print("退出 Home狀態");
end
---@type BaseFSMState
local sceneBattleFSMState = BaseFSMState.New(SceneFSMStateDefine.Battle);
sceneBattleFSMState.OnEnter = function()
print("進入 Battle狀態");
end
sceneBattleFSMState.OnLeave = function()
print("退出 Battle狀態");
end
---------- 實體化 場景狀態機 ----------
print("---------- 構造 FSM ----------");
local sceneFSM = BaseFSM.New();
sceneFSM:AddState(sceneLoginFSMState);
sceneFSM:AddState(sceneHomeFSMState);
sceneBattleFSMState:SetEntryCondition(function()
--設定Battle狀態的切換條件:僅當在Home狀態時才可切換至Battle
return sceneFSM:GetCurrentState() == sceneHomeFSMState;
end)
sceneFSM:AddState(sceneBattleFSMState);
print("---------- 設定 FSM初始狀態為 Login ----------");
sceneFSM:SetStartState(SceneFSMStateDefine.Login);
print("---------- 切換 FSM狀態為 Battle ----------");
sceneFSM:ChangeState(SceneFSMStateDefine.Battle);
print("---------- 切換 FSM狀態為 Home ----------");
sceneFSM:ChangeState(SceneFSMStateDefine.Home);
print("---------- 切換 FSM狀態為 Battle ----------");
sceneFSM:ChangeState(SceneFSMStateDefine.Battle);
--[[
OUTPUT:
---------- 構造 FSM ----------
---------- 設定 FSM初始狀態為 Login ----------
進入 Login狀態
---------- 切換 FSM狀態為 Battle ----------
---------- 切換 FSM狀態為 Home ----------
退出 Login狀態
進入 Home狀態
---------- 切換 FSM狀態為 Battle ----------
退出 Home狀態
進入 Battle狀態
--]]
參考文章
- 有限狀態機 - 魂淡1994
- 在Lua中實作面向物件特性——模擬類、繼承、多型 - 馬三小伙兒
- FSMKit - QFramework
- Fsm - GameFramework
- Lua中使用狀態機FSM簡單例子 - Kevin_綠豆芽
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/536233.html
標籤:其他
上一篇:NTP網路授時服務器(NTP服務器)助力智慧城市網路系統
下一篇:深度學習之卷積模型應用
