AppState Example

Hi,



I'm trying to get AppStates working in JME3 and finally got to a point where it's kinda working.

I was hoping you could look over it and check if i use it like it's meant to be or if it's just total crap :smiley:



Here is the Code:







AppTest.java

import com.jme3.app.Application;
import com.jme3.renderer.ViewPort;
import com.jme3.system.AppSettings;
import com.jme3.system.JmeSystem;
import com.jme3.system.Timer;

public class AppTest extends Application {

   private GameState te = null;
   private MenuState ms = null;
   
   public AppTest() {
      
   }

    @Override
    public void start(){
        // set some default settings in-case
        // settings dialog is not shown
        if (settings == null)
            setSettings(new AppSettings(true));

        // show settings dialog
        if (!JmeSystem.showSettingsDialog(settings))
           return;

        super.start();
    }
   
   @Override
    public void initialize() {
      // initialize the standard environment first
      super.initialize();
      
      // Create the States
      ms = new MenuState(this);
      te = new GameState(this);
      
      // Attach MenuState
      getStateManager().attach(ms);
    }
   
   
   @Override
    public void update() {
        super.update();
        float tpf = timer.getTimePerFrame() * speed;

        // update states
        stateManager.update(tpf);

        // render states
        stateManager.render(renderManager);

        renderManager.render(tpf);
    }
   

   public void loadMenu() {
      getStateManager().detach(te);
      getStateManager().attach(ms);
   }
   
   
   public void loadGame() {
      getStateManager().detach(ms);
      getStateManager().attach(te);
   }
   
   
   
   public ViewPort getViewPort() {
      return viewPort;
   }
   
   public ViewPort getGUIViewPort() {
      return guiViewPort;
   }
   
   
   public Timer getTimer() {
      return timer;
   }
   
   
   public static void main(String... args) {
      new AppTest().start();
   }
}




GameState.java

import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.FlyByCamera;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.Material;
import com.jme3.material.RenderState;
import com.jme3.math.Vector3f;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Geometry;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.scene.shape.Box;
import com.jme3.texture.Texture;

public class GameState extends AbstractAppState {

   protected Node rootNode = new Node("Root Node");
    protected Node guiNode = new Node("Gui Node");

    protected BitmapText fpsText;
    protected BitmapText menuText;
    protected BitmapFont guiFont;

    protected FlyByCamera flyCam;
   
    private AppTest game = null;
   
    private AppActionListener actionListener = new AppActionListener();
   
    public GameState(AppTest game) {
       this.game = game;
    }
   
    private class AppActionListener implements ActionListener {
        public void onAction(String name, boolean value, float tpf) {
            if (!value)
                return;

            if (name.equals("SIMPLEAPP_Exit")){
                game.stop();
            }else if (name.equals("SIMPLEAPP_Memory")){
                game.loadMenu();
            }
        }
    }
   
    public void loadText(){
        guiFont = game.getAssetManager().loadFont("Interface/Fonts/Default.fnt");
        fpsText = new BitmapText(guiFont, false);
        fpsText.setSize(guiFont.getCharSet().getRenderedSize());
        fpsText.setLocalTranslation(0, fpsText.getLineHeight(), 0);
        fpsText.setText("Frames per second");
        guiNode.attachChild(fpsText);
       
        menuText = new BitmapText(guiFont, false);
        menuText.setSize(guiFont.getCharSet().getRenderedSize());
        menuText.setLocalTranslation(0, (game.getContext().getSettings().getHeight()/2f)-(menuText.getLineHeight()/2f), 0);
        menuText.setText("Press [M] to go back to the Menu");
        guiNode.attachChild(menuText);
       
    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        super.initialize(stateManager, app);

        // enable depth test and back-face culling for performance
        app.getRenderer().applyRenderState(RenderState.DEFAULT);

        guiNode.setQueueBucket(Bucket.Gui);
        guiNode.setCullHint(CullHint.Never);
        loadText();

        if (game.getInputManager() != null){
            flyCam = new FlyByCamera(game.getCamera());
            flyCam.setMoveSpeed(1f);
            flyCam.registerWithInput(game.getInputManager());

            game.getInputManager().addMapping("SIMPLEAPP_Exit", new KeyTrigger(KeyInput.KEY_ESCAPE));
            game.getInputManager().addMapping("SIMPLEAPP_Memory", new KeyTrigger(KeyInput.KEY_M));
        }
       
        // Add a simple Box
        Box boxshape1 = new Box(new Vector3f(-3f,1.1f,0f), 1f,1f,1f);
        Geometry cube = new Geometry("My Textured Box", boxshape1);
        Material mat_stl = new Material(game.getAssetManager(), "Common/MatDefs/Misc/SimpleTextured.j3md");
        Texture tex_ml = game.getAssetManager().loadTexture("Interface/Logo/Monkey.jpg");
        mat_stl.setTexture("m_ColorMap", tex_ml);
        cube.setMaterial(mat_stl);
        rootNode.attachChild(cube);
    }

    @Override
    public void update(float tpf) {
        super.update(tpf);

        int fps = (int) game.getTimer().getFrameRate();
        fpsText.setText("Frames per second: "+fps);

        // simple update and root node
        rootNode.updateLogicalState(tpf);
        guiNode.updateLogicalState(tpf);
        rootNode.updateGeometricState();
        guiNode.updateGeometricState();
    }
   
   
    public void stateAttached(AppStateManager stateManager) {
        game.getInputManager().addListener(actionListener, "SIMPLEAPP_Exit",
                "SIMPLEAPP_CameraPos", "SIMPLEAPP_Memory");
       
        if(flyCam != null) flyCam.setEnabled(true);
       
        game.getViewPort().attachScene(rootNode);
        game.getGUIViewPort().attachScene(guiNode);
    }

    public void stateDetached(AppStateManager stateManager) {
       game.getInputManager().removeListener(actionListener);
        if(flyCam != null) flyCam.setEnabled(false);
       
        game.getViewPort().detachScene(rootNode);
        game.getGUIViewPort().detachScene(guiNode);
    }

    public void render(RenderManager rm) {
    }
}







MenuState.java

import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import com.jme3.font.BitmapFont;
import com.jme3.font.BitmapText;
import com.jme3.input.KeyInput;
import com.jme3.input.controls.ActionListener;
import com.jme3.input.controls.KeyTrigger;
import com.jme3.material.RenderState;
import com.jme3.renderer.RenderManager;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial.CullHint;

public class MenuState extends AbstractAppState {

   protected Node rootNode = new Node("Root Node");
    protected Node guiNode = new Node("Gui Node");

    protected BitmapText menuText;
    protected BitmapFont menuFont;
   
    private AppTest game = null;
   
    private AppActionListener actionListener = new AppActionListener();
   
    public MenuState(AppTest game) {
       this.game = game;
    }
   
    private class AppActionListener implements ActionListener {
        public void onAction(String name, boolean value, float tpf) {
            if (!value)
                return;
            // Load other state
            game.loadGame();
        }
    }
   
    public void loadFPSText(){
       menuFont = game.getAssetManager().loadFont("Interface/Fonts/Default.fnt");
       menuText = new BitmapText(menuFont, false);
       menuText.setSize(menuFont.getCharSet().getRenderedSize());
       menuText.setLocalTranslation(0, (game.getContext().getSettings().getHeight()/2f)-(menuText.getLineHeight()/2f), 0);
       menuText.setText("Frames per second");
        guiNode.attachChild(menuText);
    }

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        super.initialize(stateManager, app);
       
        // enable depth test and back-face culling for performance
        app.getRenderer().applyRenderState(RenderState.DEFAULT);

        guiNode.setQueueBucket(Bucket.Gui);
        guiNode.setCullHint(CullHint.Never);
        loadFPSText();

        // Init input
        if (game.getInputManager() != null){
            game.getInputManager().addMapping("SIMPLEAPP_Exit1", new KeyTrigger(KeyInput.KEY_ESCAPE));
        }
    }

    @Override
    public void update(float tpf) {
        super.update(tpf);

       
        menuText.setText("Press [Escape] to go to the Game-State");

        // simple update and root node
        rootNode.updateLogicalState(tpf);
        guiNode.updateLogicalState(tpf);
        rootNode.updateGeometricState();
        guiNode.updateGeometricState();
    }
   
   
    public void stateAttached(AppStateManager stateManager) {
        game.getInputManager().addListener(new AppActionListener(), "SIMPLEAPP_Exit1");
       
        game.getViewPort().attachScene(rootNode);
        game.getGUIViewPort().attachScene(guiNode);
    }

    public void stateDetached(AppStateManager stateManager) {
       game.getInputManager().removeListener(actionListener);
       
        game.getViewPort().detachScene(rootNode);
        game.getGUIViewPort().detachScene(guiNode);
    }

    public void render(RenderManager rm) {
    }
}





Did i use it right or what did I do wrong? :)
1 Like

Does something NOT work from your point of view?



This would simplify things much.



Cheers,

Tim

Everything Works Fine.

I just wanted to check if its right before i continue working on it.

I have a small Problem with the AppStates now :smiley:



I tried to use Nifty in the MenuState and it works great. I load Nifty like this in initialize(AppStateManager stateManager, Application app):

 niftyDisplay = new NiftyJmeDisplay(game.getAssetManager(),
                gamegetInputManager(),
                game.getAudioRenderer(),
                game.getGUIViewPort());
      nifty = niftyDisplay.getNifty();
      
      nifty.fromXml("chooseMarble.xml", "start");

      // attach the nifty display to the gui view port as a processor
      game.getGUIViewPort().addProcessor(niftyDisplay);



When I detach the MenuState i call
Game.getGame().getGUIViewPort().removeProcessor(niftyDisplay);
and when I attach it again I call
Game.getGame().getGUIViewPort().addProcessor(gniftyDisplay);


This works great, but if I switch to the GameState now, move around a little bit and then go back to the MenuState, it still looks good, but the Mouse seems to be displaced. So for example if the Mouse is in the Top Left Corner, nifty thinks it's maybe somewhere in the Middle.

I guess it has something to do with the Camera-Rotation, because this only happens when I rotate the Camera. I already tried to set the Location and Direction of the Camera to the values at the beginning, but the mouse still seems to be displaced.

Do you have any Idea what I'm doing wrong?

Does nobody have an Idea?

I'm still kinda stuck on this on.



I think the Problem has something to do with the Rotation of the Camera, because the mouse only seems to be displaced after i moved the Mouse and rotated the Camera (I use FlyByCamera).

So I checked in FlyByCamera what happens when I move the Mouse, but the only thing that changed were the Axes. So I tried changing them back to the Default-Values as soon as I switch back to the Menu like this:

getCamera().setAxes(new Vector3f(-1,0,0), new Vector3f(0,1,0), new Vector3f(0,0,-1));
getCamera().update();



But still no change.

So I'm a little confused, because the Axes seems to be the only thing that changes when I move the Mouse and rotate the Camera, but the Mouse still seems to be displaced after I rotate the Camera.

Do you have any Idea what I'm missing?
Every hint is appreciated :)

Sorry for the third post, but I just wanted to let you know what went wrong. (It only took me 3 days and crashing Eclipse a couple of times to figure it out :D)



When I switched to the GameState I hid the Mouse like this:

getContext().getMouseInput().setCursorVisible(false);



And when I switched back to MenuState I did the same thing, except with true.

That was basically my mistake. I replaced it with this:

getInputManager().setCursorVisible(false);


And everything works just fine.

Who knew hiding the Mouse the wrong way could cause such weird behavior? :D
1 Like