Help understanding GameStates

Well, I just need a little help to understand how to properly format a game with using gamestates.



I have learned how to program on with the JME engine, but since I am so new I am not very innovative, sorry.



Here is my view of how I was programming games.



Extending basegame, I basically had one main class that was my game, in it I had the regular classes for launching stuff.



render - i tell all the things that need to render

update - basically update everything

initgame - initiate everything in my scene like nodes, objects, textures, physics, etc.

initsystem - initiate the camera, keybindings, inputs, the properties





now with gamestates things change alot. I basically have one class which is my manager of states and I have branches which attach to this manager. Each branch is its own gamestate.



Now, here is where things get confusing for me. I want to translate my current game into a gamestate, but I dont know what has to initiate where. since I must extend GameState to use the gamestatemanager, I lose access to things like cam, display, settings, initsystem, and stuff like that.



But, this is kind of getting off track, let me express my main problem:



What do I initiate in the gamestatemanager class and what do I initiate in the branches?

Can anyone give me pointers on having gamestates with different control and camera settings?



From the tests I have done, it seems camera is set up in the manager and then it just expresses itself onto the children, as well as keybindings and inputs. Am I correct in this statement?



Thanks for any help and sorry for the rambling post.

Hi Eggsworth,



I assume that you already read through this:



http://www.jmonkeyengine.com/wiki/doku.php?id=some_standardgame_frequently_asked_questions

http://www.jmonkeyengine.com/wiki/doku.php?id=standardgame_gamestates_and_multithreading_a_new_way_of_thinking

http://www.jmonkeyengine.com/wiki/doku.php?id=simplegame_to_standardgame







Actually I'm still thinking too single-threaded but nevertheless I try to tell you something about it for you to start:

package game;

import com.jmex.game.StandardGame;
import com.jmex.game.state.GameStateManager;

public class Main {
   
   public static StandardGame game;
   public static GameGS gameGS;
   
   public Main()
   {
      // Create StandardGame
                game = new StandardGame("YourGame");
      game.getSettings().setWidth(800);
      game.getSettings().setHeight(600);
      game.getSettings().setFullscreen(false);
      game.getSettings().setStencilBits(4);
      game.start();
      
                // create a gamestate
      gameGS = new GameGS(null);
      // Activate the game state
      gameGS.setActive(true);
      // Add it to the manager
      GameStateManager.getInstance().attachChild(gameGS);      
   }
   
   public static void main(String[] args)
   {
      new Main();
   }

}



This is something like my main-class. For Testing I suggest you to use DebugGameState cause that has already some simplegame-elements like aswd- and mouse-controls

The logic like adding stuff to your node is be done (by me) in the constructor of the gamestate. (e.g. getRootNode().attachChild(...) ). The camera you can get via DisplaySystem ( DisplaySystem.getDisplaySystem().getRenderer().getCamera() )

Update and Render you can just override:


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

   }

   @Override
   public void update(float tpf) {...}




If you want (like you said) branches you can extends your class by BasicGameStateNode there you
can add more gamestates and deactivating the parent deactivates the children as well....

Here something like a template (that you have to adjust more or less! I'm doing this with some code of
mine without testing @work):


package org.tomtro.woc.gamestates;

import com.jme.input.InputHandler;
....
import com.jmex.game.state.GameStateNode;

public class GlobalGameState extends BasicGameStateNode<GameState>{

   private Logger logger = Logger.getLogger(GlobalGameState.class.getName());
   
   public static InGameState inGameState;
   

   
   private Camera camera;
   
   public GlobalGameState(String name,Player white,Player black) {
      super(name);
      MouseInput.get().setCursorVisible(Configuration.SHOW_MOUSE);
      camera = DisplaySystem.getDisplaySystem().getRenderer().getCamera();
      camera.setLocation(Configuration.INITCAM_LOC);
      camera.setDirection(Configuration.INITCAM_DIR);
      camera.setLeft(Configuration.INITCAM_LEFT);
      camera.setUp(Configuration.INITCAM_UP);
      camera.update();
      
      
      inGameState = new InGameState(localGame);
      inGameState.setActive(true);
                // attach other gamestate
      this.attachChild(inGameState);
      
      KeyBindingManager.getKeyBindingManager().set("EXIT",KeyInput.KEY_ESCAPE);

                  rootNode.attachChild(...)    // not quite sure if that might be getRootNode().attachChild(...)
   }

   @Override
   public void update(float tpf) {
      super.update(tpf);
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("EXIT",false))
      {
         logger.info("EXIT");
      }
      
   }
   

}








Thank you very much for the information.



I will review it all and post again if I have any questions, but I think you have me straightened out.



My main problem just stems from the new way you need to approach the development of a game using gamestates.



Thanks!

hello.



I have successfully gotten my camera to work and the nodes to show up, but I keep running in to the 2 same problems.



Basically what I did was took my game which was extending basegame, and turned it into a CameraGamestate loaded under an external gamestatemanager. I changed the classes such as initGame() to a constructor and changed the update and render methods appropriatly.



But for some reason, this transition has caused my physics and keybindings to not work. I mean, some of my nodes which are being viewed are physics nodes, but the boundingphysics doesnt show and my box floats in the air instead of falling down.



How my physics is loaded is by the general setters and getters for physics space which is loaded in my constructor. I know for a fact that my physics worked before working with gamestates.



Also, as far as my keybindings go, they went from working just fine to not even being noticed (i put printline comands in each keybinding function and it doesnt output anything!)



I am at a loss as to why this is happening and any help would be appreciated.



One thing I am confused about is these called to an OpenGL thread? What exactly is that and is it what i need to be working with??



Thanks for all the help!





EDIT: also here is my code I am working with incase anyone needs to look at it



My gamestate manager class

package main;



import java.util.logging.Logger;

import main.start_game.Back;
import main.start_game.Forward;
import main.start_game.Jump;
import main.start_game.Left;
import main.start_game.Right;
import main.start_game.changelevel;

import com.jme.app.BaseGame;
import com.jme.app.SimpleGame;
import com.jme.app.AbstractGame.ConfigShowMode;
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.Timer;
import com.jmex.game.StandardGame;
import com.jmex.game.state.GameStateManager;
import com.jmex.physics.PhysicsDebugger;
import com.jmex.physics.PhysicsSpace;
import com.jmex.physics.PhysicsUpdateCallback;
import com.jmex.physics.StaticPhysicsNode;


// http://www.jmonkeyengine.com/wiki/doku.php?id=chapter_17_-_game_states
// http://www.jmonkeyengine.com/wiki/doku.php?id=gamestates_trussell_s_method

public class state_manager extends BaseGame{

   private int width, height, depth, freq;
   private boolean fullscreen;
    
   protected Timer timer1;
   public InputHandler physicsStepInputHandler;


   
    public static void main(String args[])
    {
        state_manager app = new state_manager();
        app.setConfigShowMode(ConfigShowMode.AlwaysShow,
              state_manager.class.getResource("/res/FlagRush.png"));
        app.start();
    }
 
    @Override
    protected void initGame()
    {




        
        state_1 firststate = new state_1("state1");
        start_game secondstate = new start_game("sgame");
 
        firststate.setActive(false);
        secondstate.setActive(true);
 
        GameStateManager.create();
        GameStateManager.getInstance().attachChild(firststate);
        GameStateManager.getInstance().attachChild(secondstate);
 
        KeyBindingManager.getKeyBindingManager().add("toggle", KeyInput.KEY_1);
        
        
        
    }

    public void update(float interpolation) {
       timer1.update();
       interpolation = timer1.getTimePerFrame();
      //if escape was pressed, we exit
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("exit")) {
         finished = true;
      }
        if(KeyBindingManager.getKeyBindingManager().isValidCommand("toggle", false))
        {
            if(GameStateManager.getInstance().getChild(0).isActive())
            {
                GameStateManager.getInstance().getChild(0).setActive(false);
                GameStateManager.getInstance().getChild(1).setActive(true);
            }
            else
            {
                GameStateManager.getInstance().getChild(0).setActive(true);
                GameStateManager.getInstance().getChild(1).setActive(false);
            }
        }
 
    }
 
    public void render(float interpolation) {
       Renderer r =  DisplaySystem.getDisplaySystem().getRenderer();
        GameStateManager.getInstance().render(interpolation);
      
   }
   
 
   @Override
   protected void cleanup() {
      // TODO Auto-generated method stub
      
   }

   @Override
   protected void initSystem() {
      // TODO Auto-generated method stub
      //store the properties information
      width = settings.getWidth();
      height = settings.getHeight();
      depth = settings.getDepth();
      freq = settings.getFrequency();
      fullscreen = settings.isFullscreen();
 
      try {
         display = DisplaySystem.getDisplaySystem(settings.getRenderer());
         display.createWindow(width, height, depth, freq, fullscreen);
 
         
      } catch (JmeException e) {
         e.printStackTrace();
         System.exit(1);
      }
 
      //set the background to black
      display.getRenderer().setBackgroundColor(ColorRGBA.black);
 

 
      /** Get a high resolution timer for FPS updates. */
           timer1 = Timer.getTimer();
 

 
      KeyBindingManager.getKeyBindingManager().set("exit",
            KeyInput.KEY_ESCAPE);
      

      
   }

   @Override
   protected void reinit() {
      // TODO Auto-generated method stub
      
   }


}




and here is my gamestate which I am having problems with

package main;

import java.util.logging.Logger;



import com.jme.app.BaseGame;
import com.jme.image.Texture;
import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.action.InputAction;
import com.jme.input.action.InputActionEvent;
import com.jme.input.util.SyntheticButton;
import com.jme.light.DirectionalLight;
import com.jme.math.Quaternion;
import com.jme.math.Vector3f;
import com.jme.renderer.Camera;
import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.CameraNode;
import com.jme.scene.Node;
import com.jme.scene.state.LightState;
import com.jme.scene.state.TextureState;
import com.jme.scene.state.ZBufferState;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.TextureManager;
import com.jme.util.Timer;
import com.jmex.game.state.CameraGameState;
import com.jmex.physics.DynamicPhysicsNode;
import com.jmex.physics.PhysicsDebugger;
import com.jmex.physics.PhysicsSpace;
import com.jmex.physics.PhysicsUpdateCallback;
import com.jmex.physics.StaticPhysicsNode;
import com.jmex.physics.contact.ContactInfo;
import com.jmex.physics.material.Material;
/**
 * Tutorial 2 shows how to build our own Application
 * framework for Flag Rush.
 * For Flag Rush Tutorial Series.
 * @author Mark Powell
 */
public class start_game extends CameraGameState {
   protected Timer timer;



   public CameraNode camNode;
   //this is the physics space that the game will be working off
   public PhysicsSpace physicsSpace;
   protected StaticPhysicsNode staticWorldNode;
   //sets the speed of the physics
   private float physicsSpeed = 2;
   protected boolean showPhysics;
   private boolean firstFrame = true;
   //holds the information of the PlayerPhysicsNode
   public Vector3f noder = new Vector3f(0,0,0);

   public String Game_Level;
   
   public InputHandler input = new InputHandler();
   public InputHandler physicsStepInputHandler;
   //used for jumping
    public double playerOnFloor = 100;
    public int levelchanged = 300;
    public TextureState levelonetexture;

    /**
     * helper vector for zeroing motion.
     */
    private static final Vector3f ZERO = new Vector3f( 0, 0, 0 );
    /**
     * boolean for toggling the simpleUpdate and geometric update parts of the
     * game loop on and off.
     */
    protected boolean pause;
    /**
     * Simply an easy way to get at timer.getTimePerFrame(). Also saves math cycles since
     * you don't call getTimePerFrame more than once per frame.
     */
    protected float tpf1;
   //the players physics node
   public DynamicPhysicsNode PlayerPhysicsNode;
   public Node PlayerNode;
   /**
    * Main entry point of the application
    */

 
   /**
    * During an update we only look for the escape button and update the timer
    * to get the framerate.
    */
   protected void stateUpdate(float interpolation) {
      //has something to do with updating the physics
      getPhysicsSpace().update(interpolation);
      //update the time to get the framerate
      /** Recalculate the framerate. */
        timer.update();
        /** Update tpf to time per frame according to the Timer. */
        tpf1 = timer.getTimePerFrame();
      interpolation = timer.getTimePerFrame();
      /** Check for key/mouse updates. */
      //update the keyboard input (move the player around)
        input.update(interpolation);

      
      if ( !pause ) {
            float tpf = this.tpf1;
            if ( tpf > 0.2 || Float.isNaN( tpf ) ) {
                Logger.getLogger( PhysicsSpace.LOGGER_NAME ).warning( "Maximum physics update interval is 0.2 seconds - capped." );
                tpf = 0.2f;
            }
            getPhysicsSpace().update( tpf * physicsSpeed );
        }
      if ( firstFrame )
        {
            // drawing and calculating the first frame usually takes longer than the rest
            // to avoid a rushing simulation we reset the timer
            timer.reset();
            firstFrame = false;
        }
      //sets noder, the vector3f equal to the xyz of playerphysicsnode, which is the player
      noder = PlayerPhysicsNode.getLocalTranslation();
      //sets the other player node, used to direct the camera, at the same location as playerphysics node
      PlayerNode.setLocalTranslation(noder);
      //updates this node
      PlayerNode.updateGeometricState(tpf1, true);
        /** Update controllers/render states/transforms/bounds for rootNode. */
        rootNode.updateGeometricState(tpf1, true );
        //use these to output the x,y,z of nodes
        //System.out.println("PlayerNode: " + PlayerNode.getLocalTranslation().toString());
        //System.out.println("PlayerPhysicsNode: " + PlayerPhysicsNode.getLocalTranslation().toString());
        if (playerOnFloor < 100){
           playerOnFloor = playerOnFloor + 0.25;
           //System.out.println("Time: " + playerOnFloor);
        }
        if (levelchanged < 300){
           levelchanged = levelchanged + 1;
           //System.out.println("Time: " + playerOnFloor);
        }

   }
 

   /**
    * draws the scene graph
    */
   protected void stateRender(float interpolation) {
      Renderer r = getDisplay().getRenderer();
      //Clear the screen
      r.clearBuffers();
 
      r.draw(rootNode);
      doDebug(r);
   }
   
    protected void doDebug(Renderer r) {       
        if ( showPhysics ) {
            PhysicsDebugger.drawPhysics( getPhysicsSpace(), r );
        }
    }
   /**
    * initializes the display and camera.
    */
   protected void initSystem() {

 
      /** Get a high resolution timer for FPS updates. */
           timer = Timer.getTimer();
 

 
      KeyBindingManager.getKeyBindingManager().set("exit",
            KeyInput.KEY_ESCAPE);
      
      initInput();
      
   }
 
   /**
    * initializes the scene
    */
   public start_game(String name) {      
      super(name);
      //builds the physics space
      physicsSpace = PhysicsSpace.create();
      // this shows the bounds of the physics created
        showPhysics = true;
        // we want to take in account now what was already mentioned in Lesson3:
        // forces must be applied for each physics step if you want a constant force applied
        // thus we create an input handler that gets invoked each physics step
        physicsStepInputHandler = new InputHandler();
        getPhysicsSpace().addToUpdateCallbacks( new PhysicsUpdateCallback() {
            public void beforeStep( PhysicsSpace space, float time ) {
                physicsStepInputHandler.update( time );
            }
            public void afterStep( PhysicsSpace space, float time ) {

            }
        } );
   
//      //creates the root node for the entire scene
//      rootNode = new Node("All Mesh Information");
//      //ZBufferState tells objects to be displayed in the order they are over eachother
//      ZBufferState buf = getDisplay().getRenderer().createZBufferState();
//      buf.setEnabled(true);
//      buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
//      //sets ZbufferState onto the rootnode the the entire game gets ordered correctly
//      rootNode.setRenderState(buf);
      
      //creates the node which the various levels or scenes will be loaded to.
      staticWorldNode = getPhysicsSpace().createStaticNode();
 

      //builds the player
        buildPlayer();      
        //builds the overhead camera
        buildCamera();

        Game_Level = "level_one";
        level_loader level = new level_loader();
      level.level_chooser(Game_Level, staticWorldNode, rootNode);
      //currently builds lighting. needs to be redone more intuitively. perhaps mix it in to loadtexturestates?
      buildZone();
      buildInput();
      
      //update the scene graph for rendering
      rootNode.updateGeometricState(0.0f, true);
      rootNode.updateRenderState();
      
   }
   

   /////////////////////////////////////////////////////

   /**
    *
    *  Physics Initializing stuff
    */
    protected void setPhysicsSpace(PhysicsSpace physicsSpace)
    {
        if (physicsSpace != this.physicsSpace)
        {
            if ( this.physicsSpace != null )
            {
                this.physicsSpace.delete();
                this.physicsSpace = physicsSpace;
            }
        }
    }
   
    public PhysicsSpace getPhysicsSpace(){
        return physicsSpace;
    }
   
    /**
     * @return speed set by {@link #setPhysicsSpeed(float)}
     */
    public float getPhysicsSpeed() {
        return physicsSpeed;
    }

    /**
     * The multiplier for the physics time. Default is 1, which means normal speed. 0 means no physics processing.
     * @param physicsSpeed new speed
     */
    public void setPhysicsSpeed( float physicsSpeed ) {
        this.physicsSpeed = physicsSpeed;
    }
    /////////////////////////////////////////////////

 

   /**
    * clean up the textures.
    *
    */
   public void cleanup() {

 
   }
   
   
   //builds the cameranode to be applied to follow the player
   public void buildCamera(){   
      
      // attach the CameraNode to the player node
      camNode = new CameraNode("cam node", cam);
      camNode.setCamera(cam);

      // moves the camera x,y,z coordinates currently 0,220,1 *edited need fix
      camNode.setLocalTranslation(0, 220, 1);
      PlayerNode.attachChild(camNode);
      
      //used to tell the camera where to look at
      camNode.lookAt(PlayerPhysicsNode.getLocalTranslation(), PlayerPhysicsNode.getLocalTranslation());


      

   }
   
    public void buildZone() {
       
       
          /** Set up a basic, default light. */
           DirectionalLight light = new DirectionalLight();
           light.setDiffuse(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
           light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f));
           light.setDirection(new Vector3f(1,-1,0));
           light.setEnabled(true);
    
             /** Attach the light to a lightState and the lightState to rootNode. */
           LightState lightState = getDisplay().getRenderer().createLightState();
           lightState.setEnabled(true);
           lightState.attach(light);
           rootNode.setRenderState(lightState);
   
    }
   
    public void buildPlayer(){
      //creates an instance of player.java to allow dynamic calling instead of static
      Player player = new Player();
      //builds the player mesh
       PlayerPhysicsNode = getPhysicsSpace().createDynamicNode();
       PlayerNode = new Node();
      player.buildPlayer();
      PlayerPhysicsNode.attachChild(player.playerMesh);
      //attaches the player node to the scene from player.java      
        PlayerPhysicsNode.getLocalTranslation().set( 0, 1, 0);
        // move the center of mass down to let the box land on its 'feet'
        PlayerPhysicsNode.setCenterOfMass( new Vector3f( 0, -5, 0 ) );
        PlayerPhysicsNode.updateGeometricState( 0, true);
        PlayerPhysicsNode.generatePhysicsGeometry(true);
        rootNode.attachChild(PlayerPhysicsNode);
       
        PlayerNode.setLocalTranslation(0,1,0);
        rootNode.attachChild(PlayerNode);
    }
    protected void updateInput() {
        // don't input here but after physics update
       input.update( tpf1 );
    }
   
    ///////////input
     
   public void initInput(){
      /** Assign key W to action "Forward". */
        KeyBindingManager.getKeyBindingManager().set( "Forward",
                KeyInput.KEY_W );
   }


   public void buildInput(){
     
        // register an action for the other direction, too
        physicsStepInputHandler.addAction( new Left( new Vector3f( -15, 0, 0 ) ),
                InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_A, InputHandler.AXIS_NONE, false );
        physicsStepInputHandler.addAction( new Right( new Vector3f( 15, 0, 0 ) ),
                InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_D, InputHandler.AXIS_NONE, false );
        physicsStepInputHandler.addAction( new Back( new Vector3f( 0, 0, 15 ) ),
                InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_S, InputHandler.AXIS_NONE, false );
        physicsStepInputHandler.addAction( new Forward( new Vector3f( 0, 0, -15 ) ),
                InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_W, InputHandler.AXIS_NONE, false );
       input.addAction( new Jump(),
                InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_SPACE, InputHandler.AXIS_NONE, false );
       input.addAction( new changelevel(),
                InputHandler.DEVICE_KEYBOARD, KeyInput.KEY_L, InputHandler.AXIS_NONE, true );
       
        // to move the player around we create a special material for it
        // and apply surface motion on it
        final Material playerMaterial = new Material( "player material" );
        PlayerPhysicsNode.setMaterial( playerMaterial );
        // the actual motion is applied in the MoveAction (see below)
       
    }
    public class Left extends InputAction {
       private final Vector3f direction;


        /**
         * The action get the node it should move and the direction it should move in.
         *
         * @param direction force that should be applied on each invocation of the action
         */
        public Left( Vector3f direction ) {
            // simply remember in member variables
            this.direction = direction;
        }

        /**
         * This method gets invoked upon key event
         *
         * @param evt more data about the event (we don't need it)
         */
        public void performAction( InputActionEvent evt ) {

           if ( evt.getTriggerPressed() ) {
              PlayerPhysicsNode.getMaterial().setSurfaceMotion( direction );
           }

       
           
        }
    }
    public class Right extends InputAction {
       private final Vector3f direction;


        /**
         * The action get the node it should move and the direction it should move in.
         *
         * @param direction force that should be applied on each invocation of the action
         */
        public Right( Vector3f direction ) {
            // simply remember in member variables
            this.direction = direction;
        }

        /**
         * This method gets invoked upon key event
         *
         * @param evt more data about the event (we don't need it)
         */
        public void performAction( InputActionEvent evt ) {

           if ( evt.getTriggerPressed() ) {
              PlayerPhysicsNode.getMaterial().setSurfaceMotion( direction );
           }

       
        }
    }
    public class Forward extends InputAction {
       private final Vector3f direction;


        /**
         * The action get the node it should move and the direction it should move in.
         *
         * @param direction force that should be applied on each invocation of the action
         */
        public Forward( Vector3f direction ) {
            // simply remember in member variables
            this.direction = direction;
        }

        /**
         * This method gets invoked upon key event
         *
         * @param evt more data about the event (we don't need it)
         */
        public void performAction( InputActionEvent evt ) {
           if ( evt.getTriggerPressed() ) {
              PlayerPhysicsNode.getMaterial().setSurfaceMotion( direction );
           }

        }
    }
    public class Back extends InputAction {
       private final Vector3f direction;


        /**
         * The action get the node it should move and the direction it should move in.
         *
         * @param direction force that should be applied on each invocation of the action
         */
        public Back( Vector3f direction ) {
            // simply remember in member variables
            this.direction = direction;
        }

        /**
         * This method gets invoked upon key event
         *
         * @param evt more data about the event (we don't need it)
         */
        public void performAction( InputActionEvent evt ) {

           if ( evt.getTriggerPressed() ) {
              // key goes down - apply motion
                PlayerPhysicsNode.getMaterial().setSurfaceMotion( direction );
           }
//           else {
//                // key goes up - stand still
//                PlayerPhysicsNode.getMaterial().setSurfaceMotion( ZERO );
//                // note: for a game we usually won't want zero motion on key release but be able to combine
//                //       keys in some way
//           }
       
        }
    }
    public class Jump extends InputAction {
        /**
         * This method gets invoked upon key event
         *
         * @param evt more data about the event (we don't need it)
         */
        public void performAction( InputActionEvent evt ) {
            // the only really important line: apply a force to the moved node           
            if (playerOnFloor == 100) {
               PlayerPhysicsNode.addForce( new Vector3f( 0, 900, 0 ) );
               System.out.println("Jump!");
               playerOnFloor = playerOnFloor - 100;
            }
            // note: forces are applied every physics step and accumulate until then
            //       to apply a constant force we would have to do it for each physics step! (see next lesson)
           
        }
    }
    public class changelevel extends InputAction {
       //this action switches between levels
        public void performAction( InputActionEvent evt ) {
           checklevel();
        }
       
        public void checklevel(){
            // checks to see the current level, changes to the next one.  
         if (levelchanged == 300){   
            levelchanged = 0;
            if (Game_Level == "level_one") {
               staticWorldNode.removeFromParent();
               staticWorldNode.setActive(false);
              //creates the node which the various levels or scenes will be loaded to.
              staticWorldNode = getPhysicsSpace().createStaticNode();
              
               Game_Level = "level_two";               
               level_loader level = new level_loader();
              level.level_chooser(Game_Level, staticWorldNode, rootNode);
               
            }
            else if (Game_Level == "level_two") {
               staticWorldNode.removeFromParent();
               staticWorldNode.setActive(false);
              //creates the node which the various levels or scenes will be loaded to.
              staticWorldNode = getPhysicsSpace().createStaticNode();
              
               Game_Level = "level_one";           
               level_loader level = new level_loader();
              level.level_chooser(Game_Level, staticWorldNode, rootNode);
            }

        }

        }
    }

}



Thanks for any help.

I know how confused I was when I switched to gamestates and I had the same problems. So I

know that this going on is quite hard. I think a better way to port your game is first to really understand

how gamestates are working. And then include every part to your clean gamestate.



To your code: I started to have a look but it was quite hard for me to follow (I'm already sleeping I think).



The problems with the keyboard and your dynamicnode not following gravity might be both have the same source.

I think you didn't override the CameraGameState's update(time)-method. That would be the place where to

tell the physicsspace to update also. Actually I don't know what is happening when you override the stateUpdate(…)-method…



Nevertheless I have here a gamestate for you, using physics and showing the second lesson. With that try to

go on adding your code…



The Main-Class:

package main;


import com.jmex.game.StandardGame;
import com.jmex.game.state.GameStateManager;

public class Main {
   
   public static StandardGame game;
   public static GameGS gameGS;
   
   public Main()
   {
      game = new StandardGame("Panzer - 2009 by thomas.trocha.org");
      game.getSettings().setSFX(false);
      game.getSettings().setMusic(false);
      game.getSettings().setWidth(800);
      game.getSettings().setHeight(600);
      game.getSettings().setFullscreen(false);
      game.getSettings().setStencilBits(4);
      game.start();
      gameGS = new GameGS("gs");
      // Activate the game state
      gameGS.setActive(true);
      // Add it to the manager
      GameStateManager.getInstance().attachChild(gameGS);      
   }

   
   public static void main(String[] args)
   {
      Main m = new Main();
   }

}



package main;

import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.math.Vector3f;
import com.jme.scene.shape.Box;
import com.jmex.game.state.BasicGameState;
import com.jmex.physics.DynamicPhysicsNode;
import com.jmex.physics.PhysicsSpace;
import com.jmex.physics.StaticPhysicsNode;

public class GameGS extends BasicGameState{
   
   PhysicsSpace pSpace;
   
   public GameGS(String name)
   {
      super(name);
      pSpace = PhysicsSpace.create();
      setupPhysicsLesson2();
      KeyBindingManager.getKeyBindingManager().set("TEST_COMMAND", KeyInput.KEY_L);
   }
   
   public void update(float tpf) {
      super.update(tpf);
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("TEST_COMMAND"))
      {
         System.out.println("TEST COMMAND!!! KEY L");
      }
      pSpace.update(tpf);
   }

   public void setupPhysicsLesson2()
   {
      StaticPhysicsNode staticNode = pSpace.createStaticNode();

        // attach the node to the root node to have it updated each frame
        rootNode.attachChild( staticNode );

        // now we do not create a collision geometry but a visual box
        final Box visualFloorBox = new Box( "floor", new Vector3f(), 5, 0.25f, 5 );
        // note: we have used the constructor (name, center, xExtent, yExtent, zExtent)
        //       thus our box is centered at (0,0,0) and has size (10, 0.5f, 10)

        // we have to attach it to our node
        staticNode.attachChild( visualFloorBox );

        // now we let jME Physics 2 generate the collision geometry for our box
        staticNode.generatePhysicsGeometry();

        // second we create a box that should fall down on the floor
        // as the new box should move we create a _dynamic_ physics node
        DynamicPhysicsNode dynamicNode = pSpace.createDynamicNode();
        rootNode.attachChild( dynamicNode );

        // again we create a visual box
        final Box visualFallingBox = new Box( "falling box", new Vector3f(), 0.5f, 0.5f, 0.5f );
        // note: again we have used the constructor (name, center, xExtent, yExtent, zExtent)
        //       thus our box is centered at (0,0,0) and has size (1, 1, 1)
        //       the center is really important here because we want the center of the box to lie in the center
        //       of the dynamic physics node - which is the center of gravity!

        // attach it to the dynamic node
        dynamicNode.attachChild( visualFallingBox );

        // and generate collision geometries again
        dynamicNode.generatePhysicsGeometry();

        // we have to move our dynamic node upwards such that is does not start in but above the floor
        dynamicNode.getLocalTranslation().set( 0, 5, 0 );
        // note: we do not move the collision geometry but the physics node!

        // now we have visuals for the physics and don't necessarily need to activate the physics debugger
        // though you can do it (V key) to see physics in the app      
   }

   
}


you are so awesome!



I really appreciate all the help. This has been confusing for me but I am happy to be learning about all this programming stuff.



Well, I am going to continue on my quest, and if I have any more show stoppers I will bring them up here, but hopefully I dont.



Also, I hope this thread will be useful for new people like me when they go searching for these kinds of topics.





Thanks again!

//EDIT: I found out the problem, the renderstate of my rootNode in my ingame state wasnt being updated, so yeah sorry!





Hello.



I know this has nothing to do really with gamestates itself, but rather than start a new thread with every new question, I will just keep them in here.



So, (thanks to ttrocha), I now have a simple menu and ingame state working.

With my menu state I stole the code from HelloJMEDesktop to get a button working which I could click to run an action. I altered the code to bring me into my ingame state when I click the button.



I get a problem when I do this though, because a weird effect transfers over to the ingame state. The ingame state physics nodes do not have textures applied, but they get some kind of weird blue texture with small writing on it, and if I change the color of the JMEDesktop, the color of this weird effect matches. This leads me to believe that something from the JME desktop is carrying over to my new instance, even though I go through great lengths to eliminate the menu state when the button is pressed

                button.addActionListener( new ActionListener() {
                    public void actionPerformed( ActionEvent e ) {
                        // this gets executed in swing thread
                        // alter swing components ony in swing thread!
                       JOptionPane.getFrameForComponent(desktop.getJDesktop()).dispose();
                        logger.info( "clicked!" );
                    }
                } );
                // action that gets executed in the update thread:
                button.addActionListener( new JMEAction( "my action", input ) {
                    public void performAction( InputActionEvent evt ) {
                        // this gets executed in jme thread
                        // do 3d system calls in jme thread only!
                       
                       game gamestate = new game("gs");
                       GameStateManager.getInstance().getChild(0).setActive(false);
                       GameStateManager.getInstance().detachChild(0);
                       
                       GameStateManager.getInstance().attachChild(gamestate);
                       
                        GameStateManager.getInstance().getChild(0).setActive(true);

                    }
                });



I dispose of 'desktop' and setActive(false) menu state, then I detach the child as well, but somehow it still comes over. When I activate the ingame state first I do not get this weird texture, unless i then open menu state and then come back to ingame state, where the oddity reappears.

Attached is a screenshot

If anyone can help me out ide appreciate it alot. Thanks!

(and here is the source for my menu state)

package main3;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.logging.Logger;

import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;

import jmetest.awt.swingui.HelloJMEDesktop;

import com.jme.input.InputHandler;
import com.jme.input.KeyBindingManager;
import com.jme.input.KeyInput;
import com.jme.input.MouseInput;
import com.jme.input.action.InputActionEvent;
import com.jme.math.FastMath;
import com.jme.math.Vector3f;
import com.jme.renderer.Renderer;
import com.jme.scene.Node;
import com.jme.scene.Spatial;
import com.jme.scene.shape.Box;
import com.jme.system.DisplaySystem;
import com.jmex.awt.swingui.JMEAction;
import com.jmex.awt.swingui.JMEDesktop;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.GameStateManager;
import com.jmex.physics.DynamicPhysicsNode;
import com.jmex.physics.PhysicsSpace;
import com.jmex.physics.StaticPhysicsNode;

public class menu extends BasicGameState{
   
    private static final Logger logger = Logger.getLogger(HelloJMEDesktop.class
            .getName());

    /**
     * Handles our mouse/keyboard input.
     */
    protected InputHandler input = new InputHandler();;
    JMEDesktop desktop = new JMEDesktop( "desktop", 500, 400, input );
   
   public menu(String name)
   {
      super(name);

      initgame();
      KeyBindingManager.getKeyBindingManager().set("TEST_COMMAND", KeyInput.KEY_L);
   }
   
   public void update(float tpf) {
      super.update(tpf);
      input.update( tpf );
      if (KeyBindingManager.getKeyBindingManager().isValidCommand("TEST_COMMAND"))
      {
         System.out.println("TEST COMMAND!!! KEY L");
      }

   }

   public void initgame(){

        rootNode.setRenderQueueMode( Renderer.QUEUE_ORTHO );

        // create the desktop Quad
        
        // and attach it to the gui node
        rootNode.attachChild( desktop );
        // center it on screen
        desktop.getLocalTranslation().set( DisplaySystem.getDisplaySystem().getRenderer().getWidth() / 2 - 30, DisplaySystem.getDisplaySystem().getRenderer().getHeight() / 2 + 50, 0 );

        // perform all the swing stuff in the swing thread
        // (Only access the Swing UI from the Swing event dispatch thread!
        // See SwingUtilities.invokeLater()
        // and http://java.sun.com/docs/books/tutorial/uiswing/concurrency/index.html for details.)
        SwingUtilities.invokeLater( new Runnable() {
            public void run() {
                // make it transparent blue
                desktop.getJDesktop().setBackground( new Color( 0, 0, 1, 0.2f ) );

                // create a swing button
                final JButton button = new JButton( "Enter Game" );
                // and put it directly on the desktop
                desktop.getJDesktop().add( button );
                // desktop has no layout - we layout ourselfes (could assign a layout to desktop here instead)
                button.setLocation( 200, 200 );
                button.setSize( button.getPreferredSize() );
                // add some actions
                // standard swing action:
                button.addActionListener( new ActionListener() {
                    public void actionPerformed( ActionEvent e ) {
                        // this gets executed in swing thread
                        // alter swing components ony in swing thread!
                       JOptionPane.getFrameForComponent(desktop.getJDesktop()).dispose();
                        logger.info( "clicked!" );
                    }
                } );
                // action that gets executed in the update thread:
                button.addActionListener( new JMEAction( "my action", input ) {
                    public void performAction( InputActionEvent evt ) {
                        // this gets executed in jme thread
                        // do 3d system calls in jme thread only!
                       
                       game gamestate = new game("gs");
                       GameStateManager.getInstance().getChild(0).setActive(false);
                       GameStateManager.getInstance().detachChild(0);
                       
                       GameStateManager.getInstance().attachChild(gamestate);
                       
                        GameStateManager.getInstance().getChild(0).setActive(true);

                    }
                });
            }
        } );

        // don't cull the gui away
        rootNode.setCullHint( Spatial.CullHint.Never );
        // gui needs no lighting
        rootNode.setLightCombineMode( Spatial.LightCombineMode.Off );
        // update the render states (especially the texture state of the deskop!)
        rootNode.updateRenderState();
        // update the world vectors (needed as we have altered local translation of the desktop and it's
        //  not called in the update loop)
        rootNode.updateGeometricState( 0, true );

        // finally show the system mouse cursor to allow the user to click our button
        MouseInput.get().setCursorVisible( true );
   
   }

   
}

ok, well, I am having problems when it comes to shutting down the game. I can get the game to close correctly, but for some reason, depending on which gamestate I am in when i call Main.quit();, which runs StandardGame.finish();, it doesnt close the process javaw.exe, which takes a ton of my memory! (like 80,000 Kbs of memory)



When I call Main.quit(); from my main menu button that you can press, javaw.exe shuts down after the game closes, but if I call Main.quit(); from a different game state (a lobby menu) than it doesnt shut down javaw.exe and they build up causing my computer to chug.



How can I make it properly shut down?





Also, I have one other question which is alluding me, when I am working with swing, how can I center stuff on my screen like a button or a JMEDesktop?



Thanks!





//edit: I was concered about this javaw.exe taking up so much memory, so I did a little test.

I noticed that each time I go from one gamestate to another (which constitutes detaching the previous node from GameStateManager, setting the previous node = null; and building and attaching a new Node) that it takes up more memory each time. What could be causing this memory leak? Is setActive(false); detachChild(gamestatenode); and gamestatenode = null; not enough to remove the gamestate from memory? ughh, any help would be appreciated.



//edit2: I also cut out the JMEDesktop out of my gamestates, and while there is still a memory leak, it is small (100 Kbs or less per memory state) instead of 20 MB's or more per state with JMEDesktop involved. What is up with that?

bump  :mrgreen:



i am sorta wondering the same thing as you last post… no answer, but would like to see one if it exists…

Hi,
I dont know if my problem is related but when I call System.exit(0); the javaw process continues to remain in memory.

I’ve tried a clean shutdown, ie ensuring all frames are finalized but javaw process still remains in memory after System.exit(0);

Please help…

This post is pretty old, I don’t know if it’s valid.

Did you try to connect to it via jconsole or jvisualvm and check the state of Thread ?

Ignore my post. I found some open streams via jstack . Once I closed these before System.exit(0); the javaw removes itself from memory.