Привет, сообщество переполнения стека! Ооо, я пытаюсь реализовать базовый FSM для ИИ в моей игре Roblox на основе этой диаграммы FSM, которую я сделал. Я покажу модули после диаграммы и пример того, как я использую их в своем модуле NPC. Я рассмотрел множество реализаций FSM на других языках, которые выглядят проще, потому что я довольно новичок в Lua. Это похоже на приличное начало реализации FSM? Если нет, что я могу улучшить, и какие функции наиболее часто используются в FSM? Я пытаюсь разобраться с моделью FSM, так как я буду работать над играми с ИИ и не хочу безумных сумм, если, иначе, булевы и т. Д. ... Спасибо всем, кто может дать мне больше понимания того, как я можете изучить этот предмет больше!
Диаграмма
![AI FSM Diagram](https://i.imgur.com/mjXQbMx.png)
Состояние модуля:
local State = {}
State.__index = State
function State:New()
local newState = {
Init = function() print("Init ran") end,
Update = function() print("Updating") end,
Enter = function() print("Entering") end,
Exit = function() print("Exiting") end,
}
setmetatable(newState, self)
print("Created new state")
return newState
end
return State
StateMachine Модуль:
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local State = require(ReplicatedStorage:WaitForChild("State"))
local StateMachine = {}
StateMachine.__index = StateMachine
function StateMachine:Create()
local machine = {}
machine.initState = State:New()
machine.currentState = machine.initState
machine.currentState.Init()
setmetatable(machine, self)
return machine
end
function StateMachine:Update()
if self.currentState ~= nil then
self.currentState:Update()
end
end
function StateMachine:SetState(state)
assert(state ~= nil, "Cannot set a nil state.")
self.currentState:Exit()
self.currentState = state
self.currentState.Init()
self.currentState.Enter()
end
return StateMachine
Вот как я использую свою версию FSM.
Пример:
newZombie.stateMachine = StateMachine:Create()
newZombie.idleState = State:New()
newZombie.idleState.Init = function()
print("idle state init")
end
newZombie.idleState.Enter = function()
print("idle state enter!")
end
newZombie.idleState.Update = function()
print("idle state updating!")
if not newZombie.target then
print("Getting target")
newZombie.target = newZombie:GetNearestTarget()
end
if newZombie.zombieTarget then
print("Found target")
newZombie.stateMachine:SetState(newZombie.chaseState)
end
end
newZombie.chaseState = State:New()
newZombie.chaseState.Init = function()
print("chaseState init")
end
newZombie.chaseState.Enter = function()
print("chaseState enter")
end
newZombie.chaseState.Update = function()
print("chaseState updating!")
if newZombie.target then
local direction = (newZombie.target.Position - newZombie.rootPart.Position).Unit * 0.5
local distanceToTarget = (newZombie.target.Position - newZombie.rootPart.Position).magnitude
local MAX_ATTACK_RADIUS = 4
local ray = Ray.new(newZombie.rootPart.Position, (newZombie.target.Position - newZombie.rootPart.Position).Unit * 500)
local ignoreList = {}
for i, v in pairs(ZombiesServerFolder:GetChildren()) do
table.insert(ignoreList, v)
end
local hit, position, normal = Workspace:FindPartOnRayWithIgnoreList(ray, ignoreList)
if not hit.Parent:FindFirstChild("Humanoid") then
print("Walk Path")
end
if distanceToTarget >= MAX_ATTACK_RADIUS then
newZombie.rootPart.CFrame = newZombie.rootPart.CFrame + direction
else
newZombie.stateMachine:SetState(newZombie.attackState)
end
else
newZombie.stateMachine:SetState(newZombie.idleState)
end
end
newZombie.attackState = State:New()
newZombie.attackState.Init = function()
print("attackState init")
end
newZombie.attackState.Enter = function()
print("attackState enter")
end
newZombie.attackState.Update = function()
print("attackState updating!")
if newZombie.target then
local distanceToTarget = (newZombie.target.Position - newZombie.rootPart.Position).magnitude
local MAX_ATTACK_RADIUS = 4
if distanceToTarget >= MAX_ATTACK_RADIUS then
newZombie.stateMachine:SetState(newZombie.chaseState)
end
end
end
----------------------------------------------------
---- STARTING STATE ----
----------------------------------------------------
newZombie.stateMachine:SetState(newZombie.idleState)
----------------------------------------------------
Также в функции обновления NPC я обновляю функцию обновления текущего состояния конечных автоматов.
if self.stateMachine then
self.stateMachine:Update()
end