# Simple AppStates Demo

This demo is a simple example of how you use AppStates to toggle between a StartScreen and a SettingsScreen (press RETURN) while the game is paused, and start the game by switching to a GameRunning state (press BACKSPACE).

There are four files, Main.java, GameRunningState.java, StartScreenState.java, SettingsScreenState.java.

## Main.java

    package chapter04.appstatedemo;

    import com.jme3.app.SimpleApplication;
    import com.jme3.input.KeyInput;
    import com.jme3.input.controls.ActionListener;
    import com.jme3.input.controls.KeyTrigger;
    import com.jme3.input.controls.Trigger;

    /**
     * This demo shows a simple "game" with three AppStates. Instead of game content,
     * it just displays three cubes on different backgrounds.
     * <ul>
     * <li>StartScreenState: This state is enabled
     *     when the user starts the application, or the the game is paused.
     *     Press BACKSPACE to return to the game, press RETURN to go to Settings.</li>
     * <li>GameRunningState: This state shows the game content and is enabled while the game is running.
     *     Press BACKSPACE to pause and return to the start screen.</li>
     * <li>SettingsScreenState: This Settings screen state can be reached from the start screen
     *     Press RETURN to toggle it on and off.</li>
     * </ul>
     */
    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;

      /** Start the jMonkeyEngine application */
      public static void main(String[] args) {
        Main app = new Main();
        app.start();
      }

      /**
       * initialize the scene here
       */
      @Override
      public void simpleInitApp() {
        setDisplayFps(false);
        setDisplayStatView(false);

        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"});
      }

      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 simpleUpdate(float tpf) {}

    }

## GameRunningState.java

    package chapter04.appstatedemo;

    import com.jme3.app.Application;
    import com.jme3.app.SimpleApplication;
    import com.jme3.app.state.AbstractAppState;
    import com.jme3.app.state.AppStateManager;
    import com.jme3.asset.AssetManager;
    import com.jme3.font.BitmapFont;
    import com.jme3.font.BitmapText;
    import com.jme3.material.Material;
    import com.jme3.math.ColorRGBA;
    import com.jme3.math.Vector3f;
    import com.jme3.renderer.ViewPort;
    import com.jme3.scene.Geometry;
    import com.jme3.scene.Node;
    import com.jme3.scene.shape.Box;

    /**
     * A template how to create an Application State. This example state simply
     * changes the background color depending on the camera position.
     */
    public class GameRunningState extends AbstractAppState {

      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.Blue;

      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);

        /** Load this scene */
        viewPort.setBackgroundColor(backgroundColor);

        Box mesh = new Box(Vector3f.ZERO, 1, 1, 1);
        Geometry geom = new Geometry("Box", mesh);
        Material mat = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Green);
        geom.setMaterial(mat);
        geom.setLocalTranslation(1, 0, 0);
        localRootNode.attachChild(geom);

        /** Load the HUD*/
        BitmapFont guiFont = assetManager.loadFont(
                "Interface/Fonts/Default.fnt");
        BitmapText displaytext = new BitmapText(guiFont);
        displaytext.setSize(guiFont.getCharSet().getRenderedSize());
        displaytext.move(10, displaytext.getLineHeight() + 20, 0);
        displaytext.setText("Game running. Press BACKSPACE to pause and return to the start screen.");
        localGuiNode.attachChild(displaytext);
      }

      @Override
      public void update(float tpf) {
        /** the action happens here */
        Vector3f v = viewPort.getCamera().getLocation();
        viewPort.setBackgroundColor(new ColorRGBA(v.getX() / 10, v.getY() / 10, v.getZ() / 10, 1));
        rootNode.getChild("Box").rotate(tpf, tpf, tpf);
      }

      @Override
      public void stateAttached(AppStateManager stateManager) {
        rootNode.attachChild(localRootNode);
        guiNode.attachChild(localGuiNode);
        viewPort.setBackgroundColor(backgroundColor);
      }

      @Override
      public void stateDetached(AppStateManager stateManager) {
        rootNode.detachChild(localRootNode);
        guiNode.detachChild(localGuiNode);

      }

    }

## SettingsScreenState.java

    package chapter04.appstatedemo;

    import com.jme3.app.Application;
    import com.jme3.app.SimpleApplication;
    import com.jme3.app.state.AbstractAppState;
    import com.jme3.app.state.AppStateManager;
    import com.jme3.asset.AssetManager;
    import com.jme3.font.BitmapFont;
    import com.jme3.font.BitmapText;
    import com.jme3.material.Material;
    import com.jme3.math.ColorRGBA;
    import com.jme3.math.Vector3f;
    import com.jme3.renderer.ViewPort;
    import com.jme3.scene.Geometry;
    import com.jme3.scene.Node;
    import com.jme3.scene.shape.Box;

    /**
     * A template how to create an Application State. This example state simply
     * changes the background color depending on the camera position.
     */
    public class SettingsScreenState extends AbstractAppState {

      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);

        /** Load this scene */
        viewPort.setBackgroundColor(backgroundColor);

        Box mesh = new Box(new Vector3f(-1, -1, 0), .5f, .5f, .5f);
        Geometry geom = new Geometry("Box", mesh);
        Material mat = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Red);
        geom.setMaterial(mat);
        geom.setLocalTranslation(1, 0, 0);
        localRootNode.attachChild(geom);

        /** Load the HUD */
        BitmapFont guiFont = assetManager.loadFont(
                "Interface/Fonts/Default.fnt");
        BitmapText displaytext = new BitmapText(guiFont);
        displaytext.setSize(guiFont.getCharSet().getRenderedSize());
        displaytext.move(10, displaytext.getLineHeight() + 20, 0);
        displaytext.setText("Settings screen. Press RETURN to save "
                + "and return to start screen.");
        localGuiNode.attachChild(displaytext);
      }

      @Override
      public void update(float tpf) {
         /** the action happens here */
      }

      @Override
      public void stateAttached(AppStateManager stateManager) {
        rootNode.attachChild(localRootNode);
        guiNode.attachChild(localGuiNode);
        viewPort.setBackgroundColor(backgroundColor);
      }

      @Override
      public void stateDetached(AppStateManager stateManager) {
        rootNode.detachChild(localRootNode);
        guiNode.detachChild(localGuiNode);
      }

    }

## StartScreenState.java

    package chapter04.appstatedemo;

    import com.jme3.app.Application;
    import com.jme3.app.SimpleApplication;
    import com.jme3.app.state.AbstractAppState;
    import com.jme3.app.state.AppStateManager;
    import com.jme3.asset.AssetManager;
    import com.jme3.font.BitmapFont;
    import com.jme3.font.BitmapText;
    import com.jme3.material.Material;
    import com.jme3.math.ColorRGBA;
    import com.jme3.math.Vector3f;
    import com.jme3.renderer.ViewPort;
    import com.jme3.scene.Geometry;
    import com.jme3.scene.Node;
    import com.jme3.scene.shape.Box;

    /**
     * A template how to create an Application State. This example state simply
     * changes the background color depending on the camera position.
     */
    public class StartScreenState extends AbstractAppState {

      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.Gray;

    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);

        /** Init this scene */
        viewPort.setBackgroundColor(backgroundColor);

        Box mesh = new Box(new Vector3f(-1,1,0), .5f,.5f,.5f);
        Geometry geom = new Geometry("Box", mesh);
        Material mat = new Material(assetManager,
                "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Yellow);
        geom.setMaterial(mat);
        geom.setLocalTranslation(1, 0, 0);
        localRootNode.attachChild(geom);

        /** Load a HUD */
        BitmapFont guiFont = assetManager.loadFont(
                "Interface/Fonts/Default.fnt");
        BitmapText displaytext = new BitmapText(guiFont);
        displaytext.setSize(guiFont.getCharSet().getRenderedSize());
        displaytext.move( 10, displaytext.getLineHeight() + 20,  0);
        displaytext.setText("Start screen. Press BACKSPACE to resume the game, "
                + "press RETURN to edit Settings.");
        localGuiNode.attachChild(displaytext);
      }

      @Override
      public void update(float tpf) {
        /** the action happens here */
      }

      @Override
      public void stateAttached(AppStateManager stateManager) {
        rootNode.attachChild(localRootNode);
        guiNode.attachChild(localGuiNode);
        viewPort.setBackgroundColor(backgroundColor);
      }

      @Override
      public void stateDetached(AppStateManager stateManager) {
        rootNode.detachChild(localRootNode);
        guiNode.detachChild(localGuiNode);
      }

    }

view online version