Passing arguments between states in a state machine?

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?

1 Like

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()

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.