How can I improve my state machine?

Hi I’m working on a game state manger for the server.
I’ve created a state machine to handle state transitions, inside of which, I stored state instances that store functions for each state.
I need for each of the state to be updated on heartbeat, however the current method I have is a little messy and feels unorganized.
What are your guys’ solution for state machines. Any advice appreciated,
(English is not my first language. sorry if i have any mistakes)

Current code

local rs = game:GetService("RunService")
local players = game:GetService("Players")

local gameStateManager = {
	currentState = nil,
	states = {},
	statePrototype = {
		name = "empty",
		onEnter = function(self) end,
		onExit = function(self) end,
	},

addState = function(self, obj)
	if not obj.name then
		warn("must provide name for a new state")
		return
	end
	
	local newState = obj or {}
	setmetatable(newState, {__index = self.statePrototype})
	self.states[obj.name] = newState
	
	print("added state: "..obj.name)
end,

changeState = function(self, state)
	if not self or not state then
		print("invalid arguments for changeState()")
		return
	end
	
	print("state changed: "..state)
	
	if self.currentState then
		self.states[self.currentState]:onExit()
	end
	self.currentState = state
	self.states[self.currentState]:onEnter()
end,
}

gameStateManager:addState(
 	    {
    	name = "intermission",
		minPlayers = 1,
		onEnter = function(self)
			self.heartbeatConn = rs.Heartbeat:Connect(
				function()
					if #players:GetPlayers() >= self.minPlayers  then
						gameStateManager:changeState("nextState")
					else
						print("waiting for players")
					end
				end
			)
		end,
		onExit = function(self)
			if self.heartbeatConn then
				self.heartbeatConn:Disconnect()
			end
		end,
	}
)

gameStateManager:addState(
	{
		name = "nextState"
	}
)

wait(3)
gameStateManager:changeState("intermission")

I have removed other states to make the code shorter

it looks quite fine the way you implemented it, what do you think is messy? however I don’t see the need for a HeartBeat checker. why not add an event listener for PlayerAdded instead?

also perhaps you want to make currentState the actual state object instead of a string? then if you want to get the current state you can save yourself a lookup.

1 Like

Thank you so much. Did not think of that :slight_smile:

Maybe I was just overthinking lol. Thanks

1 Like