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.
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.
To implement game logic:
app
object.stateManager.attach(myAppState);
), and activate and deactivate the ones you need.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.
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:
The AppState interface allows you to initialize sets of objects, and hook a sets of continously executing code into the main loop.
AppState Method | Usage |
---|---|
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. |
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 } }
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 Method | Usage |
---|---|
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.
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.