jMonkey – Game Logic and Application States

Understanding Application States

The Appstate interface is found in the com.jme3.app.state package. It allows us to control the logic of the game on a global scale. Application states are used to handle a wide variety of different situations and to simplify the simpleUpdate method. Let’s look at a few different examples of how application states are used. We can do this by moving code from simpleUpdate to an AppState object’s update method.

An AppState class is an extension of your application. AppStates have access to every field in your application. Each AppState calls an initialize and cleanup method when added and removed from the game, respectively. It also has its own update method that connects to simpleUpdate. You can specify exactly what happens when an AppState is paused and resumed. You can also use one AppState to switch between other sets of AppStates.

Once an application state is attached to a game, every time the simpleUpdate method executes, the application state’s update method is executed. This permits moving game logic to the appropriate method.

There are 5 steps to follow when creating and using an AppState:

  1. Create a new class extending AbstractAppState
  2. Implement its abstract methods
  3. Add game behaviour to the AppState’s update method
  4. Attach the AppState to the AppStateManager
  5. Detach the AppState when you are done with it

Creating an AppState Object

To illustrate this process, we will demonstrate an AppState that will create and add a rotating effect to the planetary system we created in Chapter 2. To create a new Java class for our new AppState:

  1. Right click on the package in the project window and select New > Java Class…
  2. Name the class PlanetsAppState
  3. Click Finish

We will use the same getPlanets and getSphere methods that we used in Chapter 2. These methods you can just drop into the class. The only change we are making to the getPlanets method is making the baseNode an instance variable so that we can access it from other methods in the class. Now let’s jump into the new code.

Starting at the class declaration you will notice that AppStates must extend the AbstractAppState interface. There are four methods you need to implement:  initialize, cleanup, setEnabled, and update. We will need an instance of SimpleApplication to use throughout our class, so we will declare it as a global variable called app.

public class

[you can copy|paste the code here]

public class PlanetsAppState extends AbstractAppState {

private SimpleApplication app;

private Node baseNode = new Node(“Base Node”);

 

Overriding the Base Class Methods

Now let’s start overriding the base class methods. The initialize method takes two arguments, an AppStateManager and an Application. The initialize method, shown next, has three lines. The first line invokes the base class’ initialize method. The second line assigns this class’ instance of SimpleApplication to the instance in Main, This makes it easy to access the SimpleApplication variables such as rootNode. The third line attaches the baseNode to the rootNode from the Main class.

base class methods

@Override

public void initialize(AppStateManager stateManager,

Application app) {

super.initialize(stateManager, app);

this.app = (SimpleApplication) app;

this.app.getRootNode().attachChild(getPlanets());

}

 

The cleanup method is used to get rid of anything we no longer need if we stop using our AppState. First we call the base class method using super.cleanup. This will run the code in the base class’ cleanup method. The only thing we need to do is to detach the baseNode, since we no longer need it.

cleanup

@Override

public void cleanup() {

super.cleanup();

this.app.getRootNode().detachChild(baseNode);

}

 

The setEnabled method is used to pause and resume the AppState. The only argument to this method is a boolean value that controls whether or not the AppState is paused. The first line of this method calls the base class’ setEnabled method. The remainder of the method body is simply a conditional block that handles what to do if the state is paused or enabled. We won’t be using it in this example, but it is necessary to implement all the abstract methods of a base class. Typically, application state-specific spatials are attached and detached in this method.

setenabled

@Override

public void setEnabled(boolean enabled) {

super.setEnabled(enabled);

if (enabled) {

this.app.getRootNode().attachChild(baseNode);

} else {

this.app.getRootNode().detachChild(baseNode);

}

}

 

The final method we are inheriting from AbstractAppState is the update method. This method will be called repeatedly as long as the AppState is active. This is where we apply a constant rotation to our planetary system.

Let’s add some rotation to our planetary system use the rotate method, as discussed in Chapter 2. Notice the value we will be using: (0, .01f * FastMath.DEG_TO_RAD, 0). This means that we will be applying a .01 degree rotation around the y axis, once per frame. So, if the game is running at 300 frames per second, the planetary system will rotate at 3 degrees per second. Alternatively we could use the tpf parameter to control the rotation such as: (0, 2 * tpf, 0).

override

@Override

public void update(float tpf) {

baseNode.rotate(0, .01f * FastMath.DEG_TO_RAD, 0);

}

 

 

The getPlanets and getSphere methods are shown here:

getplanets

public Node getPlanets() {

//Create Planet

Geometry centerSphere = getSphere(20, 20, 2f);

centerSphere.setLocalTranslation(0, 0, 0);

Material sphereMaterial =

new Material(app.getAssetManager(),

“Common/MatDefs/Misc/Unshaded.j3md”);

centerSphere.setMaterial(sphereMaterial);

sphereMaterial.getAdditionalRenderState().

setWireframe(true);

baseNode.attachChild(centerSphere);

 

//Create Moon

Geometry moon = getSphere(20, 20, 0.3f);

moon.setLocalTranslation(3f, 0, 0);

moon.setMaterial(sphereMaterial);

baseNode.attachChild(moon);

 

return baseNode;

}

 

public Geometry getSphere(int y, int z, float radius) {

Sphere sphere1 = new Sphere(y, z, radius);

Geometry sphere = new Geometry(“Sphere”, sphere1);

return sphere;

}

}

 

Our PlanetsAppState class is complete and ready to use.

*

This content has been taken from Chapter 4 of jMonkeyEngine 3.0 Game Development: A Practical Guide

Leave a Reply