mirror of
https://github.com/1bardesign/batteries.git
synced 2024-11-22 14:14:36 +00:00
refactored state machine to be clear about which variables and parameters are state tables, and which are name strings
breaking - changed some property and function names fixes #16
This commit is contained in:
parent
1de942daa8
commit
b44b92a32d
@ -7,8 +7,8 @@
|
||||
|
||||
- a table with enter, exit, update and draw callbacks (all optional)
|
||||
which each take the state table and varargs as arguments
|
||||
- a function
|
||||
which gets passed the current event name, the machine, and varargs as arguments
|
||||
- a plain function
|
||||
which gets passed the current event name, the machine table, and varargs as arguments
|
||||
|
||||
on changing state, the outgoing state's exit callback is called
|
||||
then the incoming state's enter callback is called
|
||||
@ -27,11 +27,11 @@ local path = (...):gsub("state_machine", "")
|
||||
local class = require(path .. "class")
|
||||
|
||||
local state_machine = class()
|
||||
function state_machine:new(states, start)
|
||||
function state_machine:new(states, start_in_state)
|
||||
self = self:init({
|
||||
states = states or {},
|
||||
current_state = "",
|
||||
start_state = start,
|
||||
current_state_name = "",
|
||||
reset_state_name = start_in_state or "",
|
||||
})
|
||||
|
||||
self:reset()
|
||||
@ -39,16 +39,17 @@ function state_machine:new(states, start)
|
||||
return self
|
||||
end
|
||||
|
||||
--get the current state table (or nil if it doesn't exist)
|
||||
function state_machine:current_state()
|
||||
return self.states[self.current_state_name]
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--internal helpers
|
||||
|
||||
function state_machine:_get_state()
|
||||
return self.states[self.current_state]
|
||||
end
|
||||
|
||||
--make an internal call
|
||||
function state_machine:_call(name, ...)
|
||||
local state = self:_get_state()
|
||||
local state = self:current_state()
|
||||
if state then
|
||||
if type(state[name]) == "function" then
|
||||
return state[name](state, ...)
|
||||
@ -60,12 +61,12 @@ function state_machine:_call(name, ...)
|
||||
end
|
||||
|
||||
--make an internal call
|
||||
-- return the call result if it isn't a valid state
|
||||
-- transition if the return value is a valid state - and return nil if so
|
||||
-- transition if the return value is a valid state name - and return nil if so
|
||||
-- return the call result if it isn't a valid state name
|
||||
function state_machine:_call_and_transition(name, ...)
|
||||
local r = self:_call(name, ...)
|
||||
if type(r) == "string" and self:has_state(r) then
|
||||
self:set_state(r, r == self.current_state)
|
||||
self:set_state(r, r == self.current_state_name)
|
||||
return nil
|
||||
end
|
||||
return r
|
||||
@ -75,7 +76,7 @@ end
|
||||
--various checks
|
||||
|
||||
function state_machine:in_state(name)
|
||||
return self.current_state == name
|
||||
return self.current_state_name == name
|
||||
end
|
||||
|
||||
function state_machine:has_state(name)
|
||||
@ -86,13 +87,13 @@ end
|
||||
--state management
|
||||
|
||||
--add a state
|
||||
function state_machine:add_state(name, data)
|
||||
function state_machine:add_state(name, state)
|
||||
if self:has_state(name) then
|
||||
error("error: added duplicate state "..name)
|
||||
else
|
||||
self.states[name] = data
|
||||
self.states[name] = state
|
||||
if self:in_state(name) then
|
||||
self:_call("enter", self)
|
||||
self:_call_and_transition("enter")
|
||||
end
|
||||
end
|
||||
|
||||
@ -102,7 +103,7 @@ end
|
||||
--remove a state
|
||||
function state_machine:remove_state(name)
|
||||
if not self:has_state(name) then
|
||||
error("error: removed missed state "..name)
|
||||
error("error: removed missing state "..name)
|
||||
else
|
||||
if self:in_state(name) then
|
||||
self:_call("exit")
|
||||
@ -114,15 +115,16 @@ function state_machine:remove_state(name)
|
||||
end
|
||||
|
||||
--hard-replace a state table
|
||||
--if do_transitions is truthy and we're replacing the current state,
|
||||
--exit is called on the old state and enter is called on the new state
|
||||
function state_machine:replace_state(name, data, do_transitions)
|
||||
local current = self:in_state(name)
|
||||
if do_transitions and current then
|
||||
-- if we're replacing the current state,
|
||||
-- exit is called on the old state and enter is called on the new state
|
||||
-- mask_transitions can be used to prevent this if you need to
|
||||
function state_machine:replace_state(name, state, mask_transitions)
|
||||
local do_transitions = not mask_transitions and self:in_state(name)
|
||||
if do_transitions then
|
||||
self:_call("exit")
|
||||
end
|
||||
self.states[name] = data
|
||||
if do_transitions and current then
|
||||
self.states[name] = state
|
||||
if do_transitions then
|
||||
self:_call_and_transition("enter", self)
|
||||
end
|
||||
|
||||
@ -131,16 +133,16 @@ end
|
||||
|
||||
--ensure a state doesn't exist; transition out of it if we're currently in it
|
||||
function state_machine:clear_state(name)
|
||||
return self:replace_state(name, nil, true)
|
||||
return self:replace_state(name, nil)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
--transitions and updates
|
||||
|
||||
--reset the machine to whatever the start state was defined at at creation
|
||||
--reset the machine state to whatever state was specified at creation
|
||||
function state_machine:reset()
|
||||
if self.start_state then
|
||||
self:set_state(self.start_state, true)
|
||||
if self.reset_state_name then
|
||||
self:set_state(self.reset_state_name, true)
|
||||
end
|
||||
end
|
||||
|
||||
@ -148,10 +150,10 @@ end
|
||||
-- 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)
|
||||
if self.current_state ~= state or reset then
|
||||
function state_machine:set_state(name, reset)
|
||||
if self.current_state_name ~= name or reset then
|
||||
self:_call("exit")
|
||||
self.current_state = state
|
||||
self.current_state_name = name
|
||||
self:_call_and_transition("enter", self)
|
||||
end
|
||||
return self
|
||||
@ -172,7 +174,7 @@ function state_machine:draw()
|
||||
self:_call("draw")
|
||||
end
|
||||
|
||||
--for compatibility when used as a state
|
||||
--for compatibility when a state machine is nested as a state in another machine
|
||||
function state_machine:enter(parent)
|
||||
self.parent = parent
|
||||
self:reset()
|
||||
|
Loading…
Reference in New Issue
Block a user