Should AppState objects always be attached to the StateManager?

I’ve re-read the apidoc for AppState and I wonder if I’m using them wrong. I have 12 appstates representing various states the game can be in. Sometimes several of them can be active at once. I attach them all when I create them and then use setEnable to turn on the ones that are active at any time.

Is this the right way to use them? Or is the intention that they are kept detached until they are needed and then detached again when another mutually exclusive state is active?

I guess this is a way of saying that I’m confused why AppStates support attachement/detachement as well enablement/disablement. I understand that initalize/cleanup is called for attachment but not for enablement. Is that the key difference?

If I’ve missed a tutorial that explain all this then I apologise and would appreciate it if someone could point me to it.

Sometimes you want to attach/detach, sometimes you want to enable/disable. Many times you want to do both.

For example, a HUD state you probably just want to enable/disable. A “single player” app state or a “multiplayer” app state you probably want to attach/detach. (And they may then add a bunch of states that they enable/disable during the game.)

Here are a few examples that use app states in various ways…

One without an ES:

One with an ES:

But any of my demos and applications will use app states in a variety of ways. Some of them are even good examples. :slight_smile:

Thanks that’s very helpful. After looking through your example code I see you have a CompositeAppState class which allows groups of AppState to be managed together and a BaseAppState for non-composites. I couldn’t see any examples of states being attached or detached but I presume that’s done by the base classes.

So I think your design is:

  • Determine groups of related states that will need to be active together
  • Designate one as the composite, the rest as components of it
  • When that state is required, attach it and all component states
  • The composite state remains enabled while it’s attached
  • The component states can be enabled and disabled as necessary
  • When switching to another composite state, the composite and all components are detached

Is that right?

I use the composite state for big things like total game state where the collection of app states between those major game states (major being like the difference between single and multi-player) need to be kept and managed together. There are occasionally times where I guess I might use them to group nested app states together, too, but I can’t think of a case off the top of my head.

Normally, composite app state is very straight-forward:
-attached: all children are attached (note: this is not the same as initialized()… the state manager will call that as appropriate… which means the parent always gets initialized first because it was attached first)
-detached: all children are detached
-enabled: by default, all children are enabled
-disabled: by default, all children are disabled.

Children can optionally be added in such a way that their own enabled/disabled state is SOMEWHAT independent of the parent’s. If the parent is enabled then the child can be enabled/disabled independently. If the parent is disabled, all children are always disabled… but the ‘independent’ ones will remember their enabled/disabled state for the next time the parent is enabled.

Basically, if you have a child that will want to be disabled and enabled while the parent is active then you then you can call: setOverrideEnabled( AppState state, boolean override ) with ‘true’. Or you can add the child overridden with: addChild( T state, boolean overrideEnable ).

CompositeAppState is part of my SiO2 library and so is available to anyone.

You can see in the examples that I use this feature in several cases like in GameSessionState:

        addChild(new InGameMenuState(false), true);
        addChild(new CommandConsoleState(), true);
        
        // For popping up a time sync debug panel
        addChild(new TimeSequenceState(), true); 

        addChild(new HelpState(), true); 
        addChild(new PlayerListState(), true); 

Where all of the various in-game popups have their enabled state managed separately.

Whether you choose to enable/disable a state or attach/detach it is really up to you, though. Mostly, if a state is going to cache some stuff (like UI panels, etc.) then it’s better to let it stay attached for as long a life as makes sense and then use enable/disable to activate it. And if your intent is to hook it to a hot-key then that’s kind of vital. initialize/cleanup can be used to register a mapping to enable/disable on the hot key.