Application States

com.jme3.app.state.AppState is a customizable jME3 interface that allows you to control the global game logic (game mechanics). To control the behaviour of a type of Spatial, see Custom Controls instead – both can be used together.

Use Case

There will be situations during your game development where you think:

Yes you can! This is what AppStates are there for. A game state can be a subset of class fields (game data), GUI elements and their interactions, a subset of input handlers, a subset of nodes in the simpleInitApp() method, a subset of actions that you branch to in the simpleUpdate() loop, a set of AppStates and Controls – or combinations thereof.

Each AppState is such a grouped subset of such game states. Each AppState has hooks that let you define what happens to this set in the following situations:

Tip: You can create AppStates that enable and disable sets of other AppStates, e.g. InGameState versus MainScreenState.

Usage

To implement game logic:

  1. You define a custom AppState and implement its behaviour in the AppState's update() method.
    • You can pass custom data as arguments in the constructor.
    • The AppState has access to everything inside the app's scope via the Application app object.
  2. Attach all AppStates to your application's AppStateManager (stateManager.attach(myAppState);), and activate and deactivate the ones you need.
  3. Create one AppState for each set of game mechanics.

When you add several AppStates to one Application and activate them, their init methods and update loops are executed in the order in which the AppStates were added.

Examples

JME3 comes with a BulletAppState that implements Physical behaviour (using the jBullet library). You, for example, could write an Artificial Intelligence AppState to control all your enemy units. Existing examples in the code base include:

AppState

The AppState interface allows you to initialize sets of objects, and hook a sets of continously executing code into the main loop.

AppState MethodUsage
stateAttached(asm)
stateDetached(asm)
The AppState knows when it is attached to, or detached from, the AppStateManager, and triggers these two methods. Here you implement what happens then.
initialize(asm,app)The RenderThread initialized the AppState and then calls this method. Here you implement initSimpleApp()-style initialization code.
isInitialized()Your implementations of this interface should return the correct respective boolean value.
setActive(true)
setActive(false)
Temporarily enables or disables an AppState.
isActive()Test whether AppState is enabled or disabled. Your implementation should consider the boolean.
update(float tpf)Here you implement the behaviour that you want to hook into the simpleUpdate() loop.
cleanup()Called when when the AppState is de-initialized. Here you implement what clean-up code for this state.
render(RenderManager rm)Renders the state, plus your optional customizations.
postRender()Called after all rendering commands are flushed, including your optional customizations.

AbstractAppState

The AbstractAppState class already implements some common methods and makes creation of custom AppStates a bit easier: isInitialized(), setActive(), isActive(), cleanUp(). Just extend it and override the remaining AppState methods. Definition:

public class MyAppState extends AbstractAppState {
    private Node x = new Node("x"); // some class field
    private SimpleApplication app;
 
    public Node getX(){
        return x;                    // implement custom methods for this field
    }
 
    @Override
    public void update(float tpf) {
        x.doSomething();             // call some methods here
    }
 
    @Override
    public void initialize(AppStateManager stateManager, Application app) {
      super.initialize(stateManager, app); 
      this.app=(SimpleApplication)app;
      app.doSomething();             // call some methods elsewhere
    }
}

AppStateManager

The com.jme3.app.state.AppStateManager holds the list of AppStates for an application. AppStateManager ensures that active AppStates are updated and rendered. When an AppState is attached, AppStateManager calls its stateAttached() method. When an AppState is detached, AppStateManager calls its stateDetached() method. There is one AppStateManager per application. You can attach several AppStates to one AppStateManager, but the same state can only be attached once.

AppStateManager MethodUsage
hasState(s)Is AppState s attached?
getState(Class<T> stateClass)Returns the first state that is an instance of a subclass of the specified class.

The AppStateManager's update(), render(), postRender(), and cleanUp() methods are internal, users never call them directly.

Best Practices

You can only change AppStates, or read and write to them, from certain places: In a Control's update() method, in an AppState's update() method, and in the SimpleApplication's simpleUpdate() loop (or the Application's update() loop). To get data from the AppState MyAppState:

app.getState(MyAppState.class).getInfoAboutSomething();

To pass new data into the AppState MyAppState:

app.getState(MyAppState.class).setSomething(blah);

To trigger a one-off method in the AppState MyAppState:

app.getState(MyAppState.class).doSomeMoreStuff();

Don't mess with the AppState from other places, because from other methods you have no control over the order of updates. You don't know when (during which half-finished step of an update), your call was received.

view online version