Hello. Longtime no see, Jmonkeys, huh!
So I’ve been starting to create a new game. And for this game this time around I wanted to properly use AppStates together with Nifty.
The best solution in the tutorials section is this: http://wiki.jmonkeyengine.org/doku.php/jme3:advanced:nifty_gui_scenarios
But it only explains it conceptually. And yes we all know the concept it is pretty simple. So after a bit of searching I found this: http://wiki.jmonkeyengine.org/doku.php/jme3:advanced:appstatesdemo but as the header of the page says, it is outdated.
So what is this post about? I’m posting what I think is an updated version of the AppState + Nifty boilerplate as per the last link I just provided on this post.
Hopefully the next programmer who sees this post will just copy and paste my example below and include it in his/her game. Also, maybe someone (including me) will update the out-dated example in the tutorial section.
Note: you have to create your own Start.xml, GameRunning.xml, Settings.xml files in order for the example below to run. These files can be empty files.
public class Main extends SimpleApplication {
private Trigger pause_trigger = new KeyTrigger(KeyInput.KEY_BACK);
private Trigger save_trigger = new KeyTrigger(KeyInput.KEY_RETURN);
private boolean isRunning = false; // starts at startscreen
private GameRunningState gameRunningState;
private StartScreenState startScreenState;
private SettingsScreenState settingsScreenState;
public static void main(String[] args) {
AppSettings settings = new AppSettings(true);
settings.setTitle("My Game");
settings.setResolution(1280, 720);
settings.setUseJoysticks(true);
Main app = new Main();
app.setSettings(settings);
app.setShowSettings(false);
app.setDisplayStatView(false);
app.setDisplayFps(false);
app.start();
}
@Override
public void simpleInitApp() {
inputManager.clearMappings();
inputManager.setCursorVisible(true);
getFlyByCamera().setEnabled(false);
startScreenState = new StartScreenState(this);
gameRunningState = new GameRunningState(this);
settingsScreenState = new SettingsScreenState(this);
stateManager.attach(startScreenState);
NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, viewPort);
Nifty nifty = niftyDisplay.getNifty();
//nifty.setDebugOptionPanelColors(true);
nifty.addXml("Interface/Start.xml");
nifty.addXml("Interface/GameRunning.xml");
nifty.addXml("Interface/Settings.xml");
nifty.gotoScreen("start");
guiViewPort.addProcessor(niftyDisplay);
gameRunningState = new GameRunningState(this);
startScreenState = new StartScreenState(this);
settingsScreenState = new SettingsScreenState(this);
stateManager.attach(startScreenState);
inputManager.addMapping("Game Pause Unpause", pause_trigger);
inputManager.addListener(actionListener, new String[]{"Game Pause Unpause"});
inputManager.addMapping("Toggle Settings", save_trigger);
inputManager.addListener(actionListener, new String[]{"Toggle Settings"});
}
@Override
public void simpleUpdate(float tpf) {
}
private ActionListener actionListener = new ActionListener() {
public void onAction(String name, boolean isPressed, float tpf) {
System.out.println("key" + name);
if (name.equals("Game Pause Unpause") && !isPressed) {
if (isRunning) {
stateManager.detach(gameRunningState);
stateManager.attach(startScreenState);
System.out.println("switching to startscreen...");
} else {
stateManager.detach(startScreenState);
stateManager.attach(gameRunningState);
System.out.println("switching to game...");
}
isRunning = !isRunning;
} else if (name.equals("Toggle Settings") && !isPressed && !isRunning) {
if (!isRunning && stateManager.hasState(startScreenState)) {
stateManager.detach(startScreenState);
stateManager.attach(settingsScreenState);
System.out.println("switching to settings...");
} else if (!isRunning && stateManager.hasState(settingsScreenState)) {
stateManager.detach(settingsScreenState);
stateManager.attach(startScreenState);
System.out.println("switching to startscreen...");
}
}
}
};
@Override
public void simpleRender(RenderManager rm) {
//TODO: add render code
/* (optional) Make advanced modifications to frameBuffer and scene graph. */
}
}
public class StartScreenState extends AbstractAppState implements ScreenController {
private ViewPort viewPort;
private Node rootNode;
private Node guiNode;
private AssetManager assetManager;
private Node localRootNode = new Node("Start Screen RootNode");
private Node localGuiNode = new Node("Start Screen GuiNode");
private final ColorRGBA backgroundColor = ColorRGBA.Yellow;
public StartScreenState(SimpleApplication app){
this.rootNode = app.getRootNode();
this.viewPort = app.getViewPort();
this.guiNode = app.getGuiNode();
this.assetManager = app.getAssetManager();
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
rootNode.attachChild(localRootNode);
guiNode.attachChild(localGuiNode);
viewPort.setBackgroundColor(backgroundColor);
/** init the screen */
}
@Override
public void update(float tpf) {
/** the action happens here */
}
@Override
public void cleanup() {
rootNode.detachChild(localRootNode);
guiNode.detachChild(localGuiNode);
super.cleanup();
}
public void bind(Nifty nifty, Screen screen) {
}
public void onStartScreen() {
}
public void onEndScreen() {
}
}
public class GameRunningState extends AbstractAppState implements ScreenController {
private ViewPort viewPort;
private Node rootNode;
private Node guiNode;
private AssetManager assetManager;
private Node localRootNode = new Node("Game Screen RootNode");
private Node localGuiNode = new Node("Game Screen GuiNode");
private final ColorRGBA backgroundColor = ColorRGBA.Green;
public GameRunningState(SimpleApplication app){
this.rootNode = app.getRootNode();
this.viewPort = app.getViewPort();
this.guiNode = app.getGuiNode();
this.assetManager = app.getAssetManager();
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
rootNode.attachChild(localRootNode);
guiNode.attachChild(localGuiNode);
viewPort.setBackgroundColor(backgroundColor);
/** init the screen */
}
@Override
public void update(float tpf) {
/** the action happens here */
}
@Override
public void cleanup() {
rootNode.detachChild(localRootNode);
guiNode.detachChild(localGuiNode);
super.cleanup();
}
public void bind(Nifty nifty, Screen screen) {
}
public void onStartScreen() {
}
public void onEndScreen() {
}
}
public class SettingsScreenState extends AbstractAppState implements ScreenController {
private ViewPort viewPort;
private Node rootNode;
private Node guiNode;
private AssetManager assetManager;
private Node localRootNode = new Node("Settings Screen RootNode");
private Node localGuiNode = new Node("Settings Screen GuiNode");
private final ColorRGBA backgroundColor = ColorRGBA.DarkGray;
public SettingsScreenState(SimpleApplication app){
this.rootNode = app.getRootNode();
this.viewPort = app.getViewPort();
this.guiNode = app.getGuiNode();
this.assetManager = app.getAssetManager();
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
rootNode.attachChild(localRootNode);
guiNode.attachChild(localGuiNode);
viewPort.setBackgroundColor(backgroundColor);
/** init the screen */
}
@Override
public void update(float tpf) {
/** the action happens here */
}
@Override
public void cleanup() {
rootNode.detachChild(localRootNode);
guiNode.detachChild(localGuiNode);
super.cleanup();
}
public void bind(Nifty nifty, Screen screen) {
}
public void onStartScreen() {
}
public void onEndScreen() {
}
}