Hello Stack Overflow社区!所以,我试图根据我制作的FSM图在我的Roblox游戏中实现AI的基本FSM。我将在图后显示模块,并举例说明如何在NPC模块中使用它。我看过许多其他语言的FSM实现,它们看起来更容易,因为我对Lua相当陌生。这看起来像是FSM实施的良好起点吗?如果不能,我可以改进什么,FSM中最常使用哪些功能?我正在努力掌握FSM模型的知识,因为我将从事AI游戏的开发,并且不希望出现大量的if,else,booleans等问题。谢谢任何能给我带来更多见解的人可以学习更多这个学科!
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
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