mirror of
https://github.com/1bardesign/batteries.git
synced 2024-11-26 15:44:35 +00:00
[modified] minor semantics of state machines, added machinery to allow them to be nested more easily, added notes
This commit is contained in:
parent
11483c52ad
commit
01713f766f
@ -12,6 +12,10 @@
|
|||||||
on draw, the current state's draw callback is called
|
on draw, the current state's draw callback is called
|
||||||
|
|
||||||
TODO: consider coroutine friendliness
|
TODO: consider coroutine friendliness
|
||||||
|
|
||||||
|
TODO: consider refactoring the callback signatures to allow using objects with methods
|
||||||
|
like update(dt)/draw() directly
|
||||||
|
current pattern means they need to be wrapped (as in :as_state())
|
||||||
]]
|
]]
|
||||||
|
|
||||||
local path = (...):gsub("state_machine", "")
|
local path = (...):gsub("state_machine", "")
|
||||||
@ -41,12 +45,27 @@ end
|
|||||||
--make an internal call
|
--make an internal call
|
||||||
function state_machine:_call(name, ...)
|
function state_machine:_call(name, ...)
|
||||||
local state = self:_get_state()
|
local state = self:_get_state()
|
||||||
if state and type(state[name]) == "function" then
|
if state then
|
||||||
|
if type(state[name]) == "function" then
|
||||||
return state[name](self, state, ...)
|
return state[name](self, state, ...)
|
||||||
|
elseif type(state) == "function" then
|
||||||
|
return state(self, name, ...)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--make an internal call and transition if the return value is a valid state
|
||||||
|
--return the value if it isn't a valid state
|
||||||
|
function state_machine:_call_and_transition(name, ...)
|
||||||
|
local r = self:_call(name, ...)
|
||||||
|
if self:has_state(r) then
|
||||||
|
self:set_state(r, r == self.current_state)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
--various checks
|
--various checks
|
||||||
|
|
||||||
@ -63,7 +82,7 @@ end
|
|||||||
|
|
||||||
--add a state
|
--add a state
|
||||||
function state_machine:add_state(name, data)
|
function state_machine:add_state(name, data)
|
||||||
if self.has_state(name) then
|
if self:has_state(name) then
|
||||||
error("error: added duplicate state "..name)
|
error("error: added duplicate state "..name)
|
||||||
else
|
else
|
||||||
self.states[name] = data
|
self.states[name] = data
|
||||||
@ -77,7 +96,7 @@ end
|
|||||||
|
|
||||||
--remove a state
|
--remove a state
|
||||||
function state_machine:remove_state(name)
|
function state_machine:remove_state(name)
|
||||||
if not self.has_state(name) then
|
if not self:has_state(name) then
|
||||||
error("error: removed missed state "..name)
|
error("error: removed missed state "..name)
|
||||||
else
|
else
|
||||||
if self:in_state(name) then
|
if self:in_state(name) then
|
||||||
@ -99,13 +118,13 @@ function state_machine:replace_state(name, data, do_transitions)
|
|||||||
end
|
end
|
||||||
self.states[name] = data
|
self.states[name] = data
|
||||||
if do_transitions and current then
|
if do_transitions and current then
|
||||||
self:_call("enter")
|
self:_call_and_transition("enter")
|
||||||
end
|
end
|
||||||
|
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--ensure a state doesn't exist
|
--ensure a state doesn't exist; transition out of it if we're currently in it
|
||||||
function state_machine:clear_state(name)
|
function state_machine:clear_state(name)
|
||||||
return self:replace_state(name, nil, true)
|
return self:replace_state(name, nil, true)
|
||||||
end
|
end
|
||||||
@ -113,23 +132,52 @@ end
|
|||||||
-------------------------------------------------------------------------------
|
-------------------------------------------------------------------------------
|
||||||
--transitions and updates
|
--transitions and updates
|
||||||
|
|
||||||
|
--set the current state
|
||||||
|
--if the enter callback of the target state returns a valid state name, then
|
||||||
|
-- it is transitioned to in turn, and so on until the machine is at rest
|
||||||
function state_machine:set_state(state, reset)
|
function state_machine:set_state(state, reset)
|
||||||
if self.current_state ~= state or reset then
|
if self.current_state ~= state or reset then
|
||||||
self:_call("exit")
|
self:_call("exit")
|
||||||
self.current_state = state
|
self.current_state = state
|
||||||
self:_call("enter")
|
self:_call_and_transition("enter")
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--perform an update
|
--perform an update
|
||||||
--pass in an optional delta time which is passed as an arg to the state functions
|
--pass in an optional delta time which is passed as an arg to the state functions
|
||||||
|
--if the state update returns a string, and we have that state
|
||||||
|
-- then we change state (reset if it's the current state)
|
||||||
|
-- and return nil
|
||||||
|
--otherwise, the result is returned
|
||||||
function state_machine:update(dt)
|
function state_machine:update(dt)
|
||||||
return self:_call("update", dt)
|
return self:_call_and_transition("update", dt)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--draw the current state
|
||||||
function state_machine:draw()
|
function state_machine:draw()
|
||||||
self:_call("draw")
|
self:_call("draw")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--wrap a state machine in a table suitable for use directly as a state in another state_machine
|
||||||
|
--upon entry, this machine will be forced into enter_state
|
||||||
|
--the parent will be accessible under m.parent
|
||||||
|
function state_machine:as_state(enter_state)
|
||||||
|
if not self._as_state then
|
||||||
|
self._as_state = {
|
||||||
|
enter = function(m, s)
|
||||||
|
self.parent = m
|
||||||
|
self:set_state(enter_state)
|
||||||
|
end,
|
||||||
|
update = function(m, s, dt)
|
||||||
|
return self:update(dt)
|
||||||
|
end,
|
||||||
|
draw = function(m, s)
|
||||||
|
return self:draw()
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
return self._as_state
|
||||||
|
end
|
||||||
|
|
||||||
return state_machine
|
return state_machine
|
Loading…
Reference in New Issue
Block a user