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.
To implement game logic:
stateManager.attach(myAppState);
) to activate it.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 hook a continously executing piece of code into the main loop.
AppState Method | Usage |
---|---|
isActive() | Test whether AppState is enabled or disabled. |
stateAttached(asm) stateDetached(asm) | The AppState knows when it is attached to, or detached from, the AppStateManager. Then it triggers these methods that you implement. |
isInitialized() | Your implementations of this interface should return the correct respective boolean value. |
initialize(asm,app) | The RenderThread initialized the AppState and then calls this method. |
setActive(true) setActive(false) | Temporarily enables or disables an AppState. |
update(float tpf) | Here you implement the behaviour that you want to hook into the main update loop. |
cleanup() | Called when when the AppState is de-initialized. |
render(RenderManager rm) | Renders the state. |
postRender() | Called after all rendering commands are flushed. |
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 public Node getX(){ return x; } @Override public void update(float tpf) { x.doSomething(); // implement behaviour } }
Usage:
public class TestAppStates extends Application { public static void main(String[] args){ TestAppStates app = new TestAppStates(); app.start(); } @Override public void initialize(){ super.initialize(); MyAppState state = new MyAppState(); stateManager.attach(state); System.out.println("Use the state's methods... " + state.getX()); } @Override public void update(){ super.update(); stateManager.update(tpf); stateManager.render(renderManager); renderManager.render(tpf); } }
Note: If you use the AppState together with a SimpleApplication-based class, then this update()
loop is already set up.
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 it 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.