I want to make a state machine for a custom character system. I have been reading on a few things about how i can approach them.
The problem is that a few people say that states should not depend on a previous state, like you’re not supposed to pass data between states because states are independent.
This brings an issue to me, what if I want to enter a “sitting” state on a chair? I would somehow have to tell the state that this specific chair is the one to be used.
Of course I could ignore what those people consider “good practice”, but I want to make my code as good as possible, what could I do in that case?
Use some sort of data all states share.
And when you create them pass the data.
So one state can set the seat member of the data and another one read it.
As an example
--!strict
type State = {
name: string;
OnStarted: () -> ();
OnCompleted: () -> ();
}
type ServerData = {
value: number?;
stateCompleted: BindableEvent;
}
local function createStateA(data: ServerData): State
local value = 0
local state: State?
state = {
name = "A";
OnStarted = function()
print("A:OnStarted")
task.delay(1, function()
data.value = value
data.stateCompleted:Fire(assert(state).name)
end)
end,
OnCompleted = function()
print("A:OnCompleted")
value += 1
end,
}
return state
end
local function createStateB(data: ServerData): State
local state: State?
state = {
name = "B";
OnStarted = function()
print("B:OnStarted data.value", data.value)
task.delay(1, function()
data.stateCompleted:Fire(assert(state).name)
end)
end,
OnCompleted = function()
print("B:OnCompleted")
end,
}
return state
end
local function createServer()
local stateCompleted = Instance.new("BindableEvent")
local data: ServerData = {
stateCompleted = stateCompleted;
}
local allStates = { createStateA(data), createStateB(data) }
local currentState: State?
stateCompleted.Event:Connect(function(stateName: string)
-- find completed state and pick next one
local nextStateIndex
for i, state in allStates do
if state.name ~= stateName then continue end
nextStateIndex = i + 1
break
end
if assert(nextStateIndex) > #allStates then
nextStateIndex = 1
end
local nextState = allStates[assert(nextStateIndex)]
assert(currentState).OnCompleted()
currentState = nextState
currentState.OnStarted()
end)
currentState = allStates[1]
currentState.OnStarted()
end
createServer()