Jump to content

State Management in scripts


Rick
 Share

Recommended Posts

State management is a very common thing for a lot of different tasks. I've made a fairly basic state management script in lua that I'm using and was thinking it would be handy if LE maybe had some state management built into Script's.

 

Each state generally has an Enter, Exit, Update (maybe Draw for 2D) function. In the LE Script's these could be named functions that we add during init. Might be nice to be able to do:

 

self.entity:AddState("reload", self.Reload_Enter, self.Reload_Exit, self.Reload_Update, self.Reload_PostRender)

 

self.entity:ChangeState("reload")

 

 

Just a thought.

Link to comment
Share on other sites

Below is the state manager script itself. It can call onEnter, onExit, onUpdate functions that you add for each state. The onUpdate can be called at intervals vs every frame if you need (think AI thinking and maybe it has some heavier processing to it that you don't want to do every frame).

 

if StateManager ~= nil then return end

StateManager = {}

function StateManager:Create(container)
local obj = {}

obj.states = {}
obj.container = container
obj.activeState = nil
obj.nextState = nil
obj.lastState = nil
obj.lastUpdate = Time:GetCurrent()

for k,v in pairs(StateManager) do
obj[k] = v
end

return obj
end

-- methods param = { onEnter = self.function, onUpdate = self.function, onExit = self.function }
function StateManager:AddState(name, methods, updateInterval)
self.states[name] = {}
self.states[name].methods = methods
self.states[name].updateInterval = updateInterval or 0
end

function StateManager:GetCurrentState()
return self.activeState
end

function StateManager:ChangeState(name)
-- this happens the FIRST time we change to the first state
if self.activeState == nil then
self.activeState = name
self.nextState = nil
else
self.nextState = name
self.lastUpdate = self.states[self.nextState].updateInterval * -2 -- make it so Update is called once right away
end

local name = self.container.entity:GetKeyValue("name")
System:Print("Changing state to "..name.." for "..name)
end

function StateManager:ChangeToLastState()
self:ChangeState(self.lastState)
end

function StateManager:Update()
if self.activeState == nil then return end

-- check for switching states
if self.nextState ~= nil then
-- exit function of current state
if self.states[self.activeState].methods.onExit ~= nil then
self.states[self.activeState].methods.onExit(self.container)
end

-- set new state
self.lastState = self.activeState -- save off the last state
self.activeState = self.nextState
self.nextState = nil

-- enter function of new state
if self.states[self.activeState].methods.onEnter ~= nil then
self.states[self.activeState].methods.onEnter(self.container)
end
end

-- update function of current state called every interval
if self.states[self.activeState].methods.onUpdate ~= nil then
if Time:GetCurrent() >= self.states[self.activeState].updateInterval + self.lastUpdate then
self.lastUpdate = Time:GetCurrent()
self.states[self.activeState].methods.onUpdate(self.container)
end
end
end

 

 

I'll have to work up an example I guess. Looking at the MonsterAI.lua it seems like it might be a good one to do with a state machine. It basically removes a bunch of if/else statements you'd normally have and directs things to the onEnter/onExit/onUpdate methods of each state and you just change between states based on what's happening.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...