查看: 39|回复: 1

[Lua] [Lua] 用状态机(FSM)管理副本流程,彻底告别 if/else 地狱

[复制链接]

46

主题

42

回帖

1212

积分

金牌会员

积分
1212
发表于 2026-6-4 23:58:07 | 显示全部楼层 |阅读模式
-- FSM.lua  有限状态机

local FSM = {}
FSM.__index = FSM

function FSM.new(initialState)
    return setmetatable({
        _state       = initialState,
        _transitions = {},  -- { fromState = { event = { to, action } } }
        _onEnter     = {},
        _onExit      = {},
    }, FSM)
end

-- 定义转换规则:from 状态下收到 event,执行 action 后进入 to 状态
function FSM:addTransition(from, event, to, action)
    if not self._transitions[from] then self._transitions[from] = {} end
    self._transitions[from][event] = { to = to, action = action }
end

function FSMnEnter(state, fn) self._onEnter[state] = fn end
function FSMnExit(state, fn)  self._onExit[state] = fn end

-- 触发事件
function FSM:trigger(event, ...)
    local trans = self._transitions[self._state]
    if not trans or not trans[event] then
        print("[FSM] 当前状态 " .. self._state .. " 无法处理事件 " .. event)
        return false
    end
    local t = trans[event]
    if self._onExit[self._state]  then self._onExit[self._state](self._state) end
    if t.action                    then t.action(...) end
    self._state = t.to
    if self._onEnter[self._state] then self._onEnter[self._state](self._state) end
    return true
end

function FSM:getState() return self._state end

return FSM

副本流程示例:


local FSM = require("FSM")

local dungeon = FSM.new("idle")

dungeon:addTransition("idle",    "start",   "prepare", function() BroadcastMap("副本准备中,30秒后开始!") end)
dungeon:addTransition("prepare", "timeout", "fighting",function() SpawnBoss("魔王") end)
dungeon:addTransition("fighting","boss_die","reward",  function() OpenChest("宝箱", 3) end)
dungeon:addTransition("fighting","timeout", "failed",  function() KickAllPlayers() end)
dungeon:addTransition("reward",  "end",     "idle",    function() ResetMap() end)
dungeon:addTransition("failed",  "end",     "idle",    function() ResetMap() end)

dungeonnEnter("fighting", function() StartTimer(600, function() dungeon:trigger("timeout") end) end)
dungeonnEnter("idle",     function() print("副本已重置,等待下次开启") end)

-- 玩家触发开启
dungeon:trigger("start")
-- Boss死亡回调
dungeon:trigger("boss_die")
-- 结算
dungeon:trigger("end")


1

主题

228

回帖

1585

积分

金牌会员

积分
1585
发表于 2026-6-5 10:18:26 | 显示全部楼层
快了快了,马上就能用VV了
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表