When do you need a StateManager?

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
User avatar
Lacotemale
Citizen
Posts: 75
Joined: Sat Mar 08, 2014 9:01 pm

When do you need a StateManager?

Post by Lacotemale »

So Ive come to the point in my game of doing menus and such. I started doing something like to this allow certain actions depending on what screen you are on.

Code: Select all

state = 'mainmenu'
Then on another area:

Code: Select all

If state == 'mainmenu' then
--blah
end
What is the difference between doing this and using a statemanager? Does everyone need a statemanager? How does a statemanager work differently to a boolean type system?
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: When do you need a StateManager?

Post by kikito »

What is the difference between doing this and using a statemanager?
Using if-else-ifs instead of a (reasonably decent) state manager has several drawbacks. The most important ones are derived from the fact that often you must make stateful decisions in several points. The typical example is when drawing and updating, but it's possible to have more.

This means that when there is a change in the state structure, you have to "go hunting": you must find change all these if-else-ifs every time a new state appears, a state is removed, or you decide to rename it (this last case is particularly insidious since there will be no warning if you forget to rename the state in one place).

With a state manager, you will not have to "hunt", because your code will look like this: currentState.update(dt) or currentState.draw()

In a way, the advantage of a state manager is similar to the one which exists in invoking a function from several places instead of copying and pasting its code in those places.
When I write def I mean function.
Rickton
Party member
Posts: 128
Joined: Tue Mar 19, 2013 4:59 pm
Contact:

Re: When do you need a StateManager?

Post by Rickton »

Another advantage is that most state managers let you draw multiple states at the same time (eg drawing a pause menu while still displaying the game screen).
Possession - Escape from the Nether Regions, my roguelike made in LÖVE for the 2013 7-Day Roguelike Challenge
And its sequel, simply called Possession , which is available on itch.io or Steam, and whose engine I've open-sourced!
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: When do you need a StateManager?

Post by Jasoco »

I write my own state stack libraries. It keeps the code cleaner. Like Rick says above, by using a stack I can layer states on top of each other and do some really cool things much easier.
User avatar
Lacotemale
Citizen
Posts: 75
Joined: Sat Mar 08, 2014 9:01 pm

Re: When do you need a StateManager?

Post by Lacotemale »

So essentially a statemanager is like a table with a getter and setter for the current state? I was thinking of writing one like that and putting a hook into the draw and update love functions to also run my state checking code.

However, I was looking at the LovelyMoon lib which seems to do things rather different. Its very clean looking they way you break your code into separate files but again you need to split your codebase up in a big way which may be bad if I change my mind about it later on.
User avatar
Jasoco
Inner party member
Posts: 3725
Joined: Mon Jun 22, 2009 9:35 am
Location: Pennsylvania, USA
Contact:

Re: When do you need a StateManager?

Post by Jasoco »

Basically. In laymans terms here's how mine would work:

The state stack manager has callbacks for all of Löve's normal callbacks (update, draw, key and mouse stuff, resize, and everything else with a love.xxx() function)

A state would be a simple table with equivalent callbacks in which you place your code for each state. So like a game state and a main menu state and a pause menu state and any other state you can think of.

When you want to switch to a state you'd push it to the stack. Which basically just means placing a reference to that state at the end of a table. Then in the stack's update and draw and other functions it runs over the stack's list of references and runs its code. (I put in checks myself that make sure a certain callback exists first and just ignores it if it doesn't just to avoid errors.

You can also go back in the stack (Remove the top state and go back to the previous one) by just removing the reference to that top state.

I also have callbacks for states being loaded, (Called when pushed) unloaded, (Called when you go back or otherwise delete a state) focused, (Called when a state is no longer the topmost) and blurred. (Called when it becomes focused again) And I can send tables back to the previous state by returning them through a states blur callback and in the previous state I place code in the focus callback to handle the commands I want to send. Basically like having a dialog that returns certain values.

It sounds more complicated but it's not really. I've rewritten a state stack library of my own three times now.

A much simpler state manager is just references to states with no stacking. (Basically each state replaces the previous so you'll want to make sure to keep some globals around to store variables for passing between states)
User avatar
shru
Prole
Posts: 26
Joined: Mon Sep 28, 2015 3:56 am
Location: Hyperborea
Contact:

Re: When do you need a StateManager?

Post by shru »

Jasoco wrote:I can send tables back to the previous state by returning them through a states blur callback and in the previous state I place code in the focus callback to handle the commands I want to send. Basically like having a dialog that returns certain values.
Would you mind providing some simple code examples or otherwise elaborating on this a little? I definitely grasp the desired result, but I'm having a little trouble figuring out the best way to actually implement this. Here's what I've come up with so far:


Code: Select all

-- sub_menu_state.lua

function SubMenuState:makeSomeSelection()
    local return_table = { selection_id = '11', selection_text = 'perform a cute twirl' }
    self:getStateManager():pop(return_table)
end

Code: Select all

-- state_manager.lua

function StateManager:pop(return_table)
     -- pop StateManager's top-most state.
    table.remove(self.state_stack)

    -- pass in the return payload returned by the previous state
    self.state_stack[#self.state_stack]:focus(return_table)
end

Code: Select all

-- main_menu_state.lua

function MainMenuState:focus(return_table_from_sub_menu)
    self:doSomethingWithTableReturnedByPrevState(return_table_from_sub_menu)
end


Hopefully this makes sense to you. (There's definitely are some problems with this pseudocode, though. For example, since SubMenu doesn't actually know whether it's the topmost state in StateManager.)
itchtwittergithub
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: When do you need a StateManager?

Post by s-ol »

shru wrote:
Jasoco wrote:I can send tables back to the previous state by returning them through a states blur callback and in the previous state I place code in the focus callback to handle the commands I want to send. Basically like having a dialog that returns certain values.
Would you mind providing some simple code examples or otherwise elaborating on this a little? I definitely grasp the desired result, but I'm having a little trouble figuring out the best way to actually implement this. Here's what I've come up with so far:


Code: Select all

-- sub_menu_state.lua

function SubMenuState:makeSomeSelection()
    local return_table = { selection_id = '11', selection_text = 'perform a cute twirl' }
    self:getStateManager():pop(return_table)
end

Code: Select all

-- state_manager.lua

function StateManager:pop(return_table)
     -- pop StateManager's top-most state.
    table.remove(self.state_stack)

    -- pass in the return payload returned by the previous state
    self.state_stack[#self.state_stack]:focus(return_table)
end

Code: Select all

-- main_menu_state.lua

function MainMenuState:focus(return_table_from_sub_menu)
    self:doSomethingWithTableReturnedByPrevState(return_table_from_sub_menu)
end


Hopefully this makes sense to you. (There's definitely are some problems with this pseudocode, though. For example, since SubMenu doesn't actually know whether it's the topmost state in StateManager.)
My library st8.lua can do this stuff: viewtopic.php?f=5&t=79943&hilit=state#p182150

Dokumentation is kind of... sparse though.

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
User avatar
Inny
Party member
Posts: 652
Joined: Fri Jan 30, 2009 3:41 am
Location: New York

Re: When do you need a StateManager?

Post by Inny »

I'm a bit mental, in my current project I have my gamestates be a coroutine that yields a drawable object back to the main thread, so that my calls into text boxes and menus are blocking.
Post Reply

Who is online

Users browsing this forum: Ahrefs [Bot], Google [Bot] and 44 guests