Это правильный способ реализовать базовый FSM в Lua для моей FSM Diagram? - PullRequest
1 голос
/ 24 апреля 2019

Привет, сообщество переполнения стека! Ооо, я пытаюсь реализовать базовый FSM для ИИ в моей игре Roblox на основе этой диаграммы FSM, которую я сделал. Я покажу модули после диаграммы и пример того, как я использую их в своем модуле NPC. Я рассмотрел множество реализаций FSM на других языках, которые выглядят проще, потому что я довольно новичок в Lua. Это похоже на приличное начало реализации FSM? Если нет, что я могу улучшить, и какие функции наиболее часто используются в FSM? Я пытаюсь разобраться с моделью FSM, так как я буду работать над играми с ИИ и не хочу безумных сумм, если, иначе, булевы и т. Д. ... Спасибо всем, кто может дать мне больше понимания того, как я можете изучить этот предмет больше!


Диаграмма

AI FSM Diagram

Состояние модуля:

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...