GameState problem

so, what's the whole problem:



initially, I insert all gamestates used in the game into the gamemanager en start the playstate.

everything goes well, but when a go (by pressing a button, in my case the M-key) to another

state and, afterwards, back to the original state, i'm unable to push the m key again…

nothing really happens…



after 'some' work I found out:



in ActionTrigger:


        public void performAction( InputActionEvent event ) {
           System.out.println(name);
            if ( name == null ||
                    KeyBindingManager.getKeyBindingManager().isValidCommand( name, allowRepeats ) ) {
                super.performAction( event );
                activate();
            }
        }



so, first, the performaction (on the superclass) is invoked, which does nothing more than:
(in my code off course)


    GameStateManager.getInstance().deactivateChildNamed(Constants.STATE_PLAY);
    GameStateManager.getInstance().activateChildNamed(Constants.STATE_OVERVIEW);      



and after this, deactivates the state, so all working fine right now!
but....

the next step in the performAction is the ActionTrigger::activate() method, which checks: '!active && inputHandler.isEnabled()', which automatically steps over because the STATE_PLAY is deactivated, so also his input
system is deactivated... But this means that the M-key action is not added, so it's not processed anymore...

How can I solve this?

Just taking a glance here, but my expectation is that you've disabled the GameState that actually does the updates on the InputHandler?



darkfrog

k, to make it more clear  :slight_smile:



Both states have their own input manager, and in both cases, they have:



        protected void onActivate() {
      mInputHandler.setEnabled(true);
   }
   
   protected void onDeactivate() {
      mInputHandler.setEnabled(false);
   }



so, i disabled the first one, and afterwards, enabled the second one

FreakyB

Yes, but are you updating the InputHandler in the update loop?



darkfrog

yep, doing that…



FreakyB

Then post more code. :stuck_out_tongue:

key, here it is



playstate:


        protected void onActivate() {
      setInputState(true);
        }
 
        protected void onDeactivate() {
      setInputState(false);
   }

        private void initInput() {
      mInputHandler = new FirstPersonHandler(mCamera, 300, 1);
      mInputKeys = new PlayInputHandler(this);
   }

        private void setInputState(boolean state) {
      mInputHandler.setEnabled(state);
      mInputKeys.setEnabled(state);
   }

        protected void stateUpdate(float tpf) {
      mInputHandler.update(tpf);
      mInputKeys.update(tpf);
   }



little explanation: using 2 inputhandlers for this state now cause it's easier to let the firstpersonhandler handle the camera movement, and let the other handle the 'special' keys

overviewstate:


        // constructor
        public OverviewState() {
                mInputHandler = new OverviewInputHandler();
      mInputHandler.setEnabled(false);
        }

        protected void stateUpdate(float tpf) {
      mInputHandler.update(tpf);
   }
   
   protected void onActivate() {
      DisplaySystem.getDisplaySystem().getRenderer().setCamera(mCamera);
      mInputHandler.setEnabled(true);
   }
   
   protected void onDeactivate() {
      mInputHandler.setEnabled(false);
   }



so, this is really all that matters!
thanks already!

FreakyB

Both states' InputHandlers have functionality for the 'M' key?

That was what i wanted…



the thing is: the playstate is when the user is really playing, but when pressing the 'M' button a map of the area is shown, so it should be possible to remove the map again by the M-key



but because it didn't work I already removed this, so now the M key is only used in the playstate!



FreakyB

Perhaps you should have a third GameState for your "global" functionality and have it with the InputHandler that handles M-press?

but shall that solve the initial problem? by now, i don't want the M-key to be enabled…



those answers of you are really good 'alternatives', but I don't think they solve the real problem…

no offence!



FreakyB

I apologize, I'm confused at what the problem is then. :o

kay, my bad :slight_smile:



tomorrow i'll post a very small demo code to produce the error!



thanks already btw!



FreakyB

okay, i managed to create the 'demo' code:



package src;

import java.util.logging.Level;

import com.jme.app.AbstractGame;
import com.jme.app.BaseGame;
import com.jme.app.GameState;
import com.jme.app.GameStateManager;
import com.jme.app.StandardGameState;
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.renderer.ColorRGBA;
import com.jme.system.DisplaySystem;
import com.jme.system.JmeException;
import com.jme.util.LoggingSystem;
import com.jme.util.Timer;

public class ProblemDemo extends BaseGame{
   
   public static String STATE_NAME_1 = "STATE1";
   public static String STATE_NAME_2 = "STATE2";
   
   /**
    * InputManager for default state (BLUE one)
    * @author FreakyB
    *
    */
   public class State1InputHandler extends InputHandler {
      public State1InputHandler() {
         setKeyBindings();
      }

      private void setKeyBindings() {
          KeyBindingManager.getKeyBindingManager().set("exit", KeyInput.KEY_ESCAPE);
          addAction( new ExitAction(), "exit", false );
         
          KeyBindingManager.getKeyBindingManager().set("showRedState", KeyInput.KEY_M);
          addAction( new showRedStateAction(), "showRedState", false );
      }

      private class ExitAction extends InputAction {
          public void performAction( InputActionEvent evt ) {
              System.exit(0);
          }
      }
      
      private class showRedStateAction extends InputAction {
         public void performAction(InputActionEvent evt) {
            GameStateManager.getInstance().deactivateChildNamed(STATE_NAME_1);
            GameStateManager.getInstance().activateChildNamed(STATE_NAME_2);
         }
      }
   }
   
   /**
    * InputManager for default state (RED one)
    * @author FreakyB
    *
    */
   public class State2InputHandler extends InputHandler {
      public State2InputHandler() {
         setKeyBindings();
      }
      
      private void setKeyBindings() {
         KeyBindingManager.getKeyBindingManager().set("LeaveState", KeyInput.KEY_ESCAPE);
         addAction( new LeaveState(), "LeaveState", false );
      }
      
      private class LeaveState extends InputAction {
         public void performAction( InputActionEvent evt) {
            GameStateManager.getInstance().deactivateChildNamed(STATE_NAME_2);
            GameStateManager.getInstance().activateChildNamed(STATE_NAME_1);
         }
      }
   }
   
   /**
    * Default state - BLUE one
    * @author FreakyB
    *
    */
   public class State1 extends StandardGameState {
      private InputHandler mInputHandler = null;
      
      public State1() {
         super(STATE_NAME_1);
         mInputHandler = new State1InputHandler();
      }
      
      protected void onActivate() {
         // enable camera
         super.onActivate();
         DisplaySystem.getDisplaySystem().getRenderer().setBackgroundColor(ColorRGBA.blue);
         mInputHandler.setEnabled(true);
      }
      
      protected void onDeactivate() {
         mInputHandler.setEnabled(false);
      }
      
      protected void stateUpdate(float tpf) {
         mInputHandler.update(tpf);
      }
      
   }
   
   /**
    * Default state - RED one
    * @author FreakyB
    *
    */
   public class State2 extends StandardGameState {
      private InputHandler mInputHandler = null;
      
      public State2() {
         super(STATE_NAME_2);
         mInputHandler = new State2InputHandler();
      }
      
      protected void onActivate() {
         // enable camera
         super.onActivate();
         DisplaySystem.getDisplaySystem().getRenderer().setBackgroundColor(ColorRGBA.red);
         mInputHandler.setEnabled(true);
      }
      
      protected void onDeactivate() {
         mInputHandler.setEnabled(false);
      }
      
      protected void stateUpdate(float tpf) {
         mInputHandler.update(tpf);
      }
   }
   
   
   // MAIN CLASS
   private Timer mTimer = null;
   private float mTPF = .0f;
   

   protected final void update(float interpolation) {
      // Recalculate the framerate.
      mTimer.update();
      mTPF = mTimer.getTimePerFrame();
      
      // Update the current game state.
      GameStateManager.getInstance().update(mTPF);
   }
   
   /**
    * This is called every frame in BaseGame.start(), after update()
    *
    * @param interpolation unused in this implementation
    * @see AbstractGame#render(float interpolation)
    */
   protected final void render(float interpolation) {   
      // Clears the previously rendered information.
      display.getRenderer().clearBuffers();
      // Render the current game state.
      GameStateManager.getInstance().render(mTPF);
   }
   
   /**
    * Creates display, sets  up camera, and binds keys.  Called in BaseGame.start() directly after
    * the dialog box.
    *
    * @see AbstractGame#initSystem()
    */
   protected final void initSystem() {
      try {
         /** Get a DisplaySystem acording to the renderer selected in the startup box. */
         display = DisplaySystem.getDisplaySystem(properties.getRenderer());
         /** Create a window with the startup box's information. */
         display.createWindow(
               properties.getWidth(),
               properties.getHeight(),
               properties.getDepth(),
               properties.getFreq(),
               properties.getFullscreen());
         /** Create a camera specific to the DisplaySystem that works with
          * the display's width and height*/         
      }
      catch (JmeException e) {
         /** If the displaysystem can't be initialized correctly, exit instantly. */
         e.printStackTrace();
         System.exit(1);
      }
      
      /** Get a high resolution timer for FPS updates. */
      mTimer = Timer.getTimer();
      
   }
   
   /**
    * Called in BaseGame.start() after initSystem().
    *
    * @see AbstractGame#initGame()
    */
   protected final void initGame() {      
      // Creates the GameStateManager. Only needs to be called once.
      GameStateManager.create();
      // Adds a new GameState to the GameStateManager. In order for it to get
      // processed (rendered and updated) it needs to get activated.
      //GameState menu = new MenuState("menu");
      ///menu.setActive(true);
      //GameStateManager.getInstance().attachChild(menu);
      
      GameState state1BLUE = new State1();
      GameState state2RED = new State2();
      
      GameStateManager.getInstance().attachChild(state1BLUE);
      GameStateManager.getInstance().attachChild(state2RED);
      
      state1BLUE.setActive(true);
   }
   
   /**
    * Empty.
    *
    * @see AbstractGame#reinit()
    */
   protected void reinit() {
   }
   
   /**
    * Cleans up the keyboard and game state system.
    *
    * @see AbstractGame#cleanup()
    */
   protected void cleanup() {
      LoggingSystem.getLogger().log(Level.INFO, "Cleaning up resources.");
      
      // Performs cleanup on all loaded game states.
      GameStateManager.getInstance().cleanup();
   }   
   
   public static void main(String[] args) {
      ProblemDemo app = new ProblemDemo();
      app.start();
   }
}



so nothing more than 2 states with their own input manager.

start the program and you'll see the BLUE-state, press the (almost famous  ;)) M-button, and the RED-state appearce, press ESCAPE, the blue state shows back, and now the problem hits...
push the M-button again but the RED state won't show up...

as mentioned before, the problem is here:


        in CommandTrigger:

        public void performAction( InputActionEvent event ) {
            if ( name == null ||
                    KeyBindingManager.getKeyBindingManager().isValidCommand( name, allowRepeats ) ) {
                super.performAction( event );
                activate();
            }
        }


        in ActionTrigger:

        public void performAction( InputActionEvent event ) {
                final int count = getActionInvocationCount();
                for ( int i=0; i < count; i++ ) {
                putTriggerInfo( event, i );
                action.performAction( event );
            }
            if ( !allowRepeats ) {
                deactivate();
            }
        }



the workflow:
CommandTrigger::performAction()
--> ActionTrigger::performAction()
        --> action.performAction()
                So, this does:
                GameStateManager.getInstance().deactivateChildNamed(STATE_NAME_1);
                GameStateManager.getInstance().activateChildNamed(STATE_NAME_2);
                which means that for state 1, the input manager is disabled by the onDeactivate() method
        --> deActivate()
--> ActionTrigger::activate()
        and here is the problem:
        if ( !active && inputHandler.isEnabled() ) ....
        the inputhandler isn't enabled anymore, cause it's been disabled in the GameState::onDeactivate() method....

I hope I made myself a little more clear now ;)
any idea how to solve it?

thanks!

FreakyB