Multiple states in a game

The flowing classes are designed to handle multiple states in a game. They were requested on the form. The code was inspired by a simuler system in "Programming rollplaying games with directx".


 
public interface GameMoad
{
    public void intm(GameStackMgr Par,Object[] prams);   
   
    public void upDate(Object[] prams);
    public void render(Object[] prams);
   
    public void deleat(Object[] prams);   
   
}



import java.util.Stack;
public class GameStackMgr {
    public Stack MoadStak;
   
    public GameStackMgr Instints;
   
    /** Creates a new instance of GameStackMgr */
    public GameStackMgr()
    {
        if(Instints==null)
            Instints=this;
        MoadStak= new Stack();
    }
   
    public GameStackMgr getGameStackMgr(){return Instints;}
   
    public GameMoad getTop()
    {
        return (GameMoad)MoadStak.peek();
    }
   
    public void push(GameMoad moad, Object[] prams)
    {
        MoadStak.push(moad);
        moad.intm(this,prams);
       
    }
   
   
    public void upDate(Object[] prams)
    {
        if(getTop()!=null)
            getTop().upDate(prams);
    }
   
    public void Render(Object[] prams)
    {
        if(getTop()!=null)
            getTop().render(prams);       
    }
   
    public void pop(Object[] prams)
    {
        if(getTop()!=null)
        {
            getTop().deleat(prams);   
            MoadStak.pop();
        }
    }
   
}



I know the spelling could be better so do not flame me for it. ://

Good work! I absolutely think jME should include this, because every game needs to shift between game states.



I noticed this system uses a Stack to handle the game states, which makes it impossible to, lets say, go from mainMenu → newGameMenu → ingame → mainMenu?



Maybe we should include another GameStateManager which uses a Hashtable?



Anyways, I fixed the spelling and made it follow the singleton pattern (there should only be one GameStateManager):

import java.util.Stack;



public class GameStateManager {

   private static GameStackManager instance;

   private Stack modeStack;   

   

   

   private GameStateManager() {

      modeStack = new Stack();

   }

   

   

   public static GameStateManager create() {

      if (instance == null) {

         instance = new GameStateManager();

      }

      return instance;

   }

   

   

   public static GameStateManager getInstance() {

      return instance;

   }

   

   

   public GameState getTop() {

      return (GameState)modeStack.peek();

   }

   

   

   public void push(GameState mode, Object[] params) {

      modeStack.push(mode);

      mode.init(params);      

   }

   

   

   public void update(Object[] params) {

      if(getTop()!= null)

         getTop().update(params);

   }

   

   

   public void render(Object[] params) {

      if(getTop()!= null)

         getTop().render(params);       

   }

   

   

   public void pop(Object[] params) {

      if(getTop()!= null) {

         getTop().delete(params);   

         modeStack.pop();

      }

   } 

}





public interface GameState {

    public void init(Object[] params);

    public void update(Object[] params);

    public void render(Object[] params);

    public void delete(Object[] params);   

}







Comments? Ideas?





/Per





EDIT: Forgot to say that each GameState does no longer need a reference to it’s parent GameStateManager due to the singleton.

As probably everybody here, I too have already written a state engine :slight_smile:



Some features I added and therefore would like to mention:


  • it is possible to either call a state (and return from it) or go to it without being able to return


  • Each state has its own input handler, so it is possible to mix FirstPersonHandler and ThirdPersonHandler (which I provided for my own purposes); plus it’s own camera and root nodes for the three render queues


  • each state has an activate and deactivate method that gets called whenever states are entered or left. That way I can register and deregister input actions
* Each state has its own input handler, so it is possible to mix FirstPersonHandler and ThirdPersonHandler (which I provided for my own purposes); plus it's own camera and root nodes for the three render queues

Yeah, each state should have its own input handler, and having its own rootNode is probably also a good thing. So a GameState should be an abstract class rather than an interface, right?

* each state has an activate and deactivate method that gets called whenever states are entered or left. That way I can register and deregister input actions

Well, from your game loop you would typically call GameStateManager.update() which in turn only updates the game state on the top of the stack (the active one), which will grab the input from it's own input handler.
"Per" wrote:
Yeah, each state should have its own input handler, and having its own rootNode is probably also a good thing. So a GameState should be an abstract class rather than an interface, right?
I made an interface, which is implemented by an abstract class - like in Swing event handlers, where you do have a XYZinterface plus a XYZadapter class implementing the interface with the typically required functionality. I like interfaces since they allow an already implemented class to additionally provide the interface.
"Per" wrote:
Well, from your game loop you would typically call GameStateManager.update() which in turn only updates the game state on the top of the stack (the active one), which will grab the input from it's own input handler.
Yep, you're right. That code is there since I created it before mojo rewrote the input handler / event thing, so I could handle several simultaneous keypresses.

I think you guys are on the right track. Having each state have it’s own… well… state would be nice. Control, display, sound in the main menu will most likely be very different than that of the main game. So, being able to manage multiple scenes, input, etc would be nice.

Definitely the right track. We use this kind of path very effectively in Dirt.

Ok, due to the above discussion I have a proposal for a new game state system:



In summary this is how it works:

  • Each state has its own Node, Camera and InputHandler.
  • No render method of a game state is needed since you just attach the stateNode to your rootNode.
  • GameStateManager uses a Hashtable to keep track of game states.
  • StandardGameState implements GameState and initializes a standard stateNode and camera, but lets the user init the input handler.



    Usage should look something like this:

init() {
    GameStateManager.create(rootNode);
    GameStateManager.getInstance().addGameState("main menu", new MainMenuState());
    GameStateManager.getInstance().switchTo("main menu");
}

update() {
    GameStateManager.getInstance().update(tpf);
    if play button is pressed {
        GameStateManager.getInstance().addGameState("ingame", new IngameState());
        GameStateManager.getInstance().switchTo("ingame");
        GameStateManager.getInstance().removeState("main menu");
    }
}


import com.jme.scene.Node;
import com.jme.renderer.Camera;

/**
 * The basic frame of a <code>GameState</code>.
 *
 * @author Per Thulin
 */
public interface GameState {
   
   /**
    * Gets called every frame by <code>GameStateManager</code>.
    * @param tpf The time since last frame.
    */
    public abstract void update(float tpf);
   
    /**
     * Gets called on removal of this game state.
     */
    public abstract void cleanup();
   
   /**
    * Gets the camera of this state.
    * @return The camera of this state.
    */
    public abstract Camera getCamera();
   
   /**
    * Gets the state node of this state.
    * @return The state node of this state.
    */
    public abstract Node getStateNode();
}


import com.jme.scene.Node;
import com.jme.system.DisplaySystem;
import com.jme.input.InputHandler;
import com.jme.renderer.Camera;

/**
 * A typical game state that initializes a rootNode and camera.
 * The input handler is left to be initialized by derived classes.
 *
 * @author Per Thulin
 */
public abstract class StandardGameState implements GameState {
   protected InputHandler input;
   protected Node stateNode;
   protected Camera cam;
   
   /**
    * Initializes rootNode and camera.
    */
   public StandardGameState() {
      stateNode = new Node("State rootNode");
      initCamera();
   }

   /**
    * Updates the InputHandler.
    * @param tpf The time since last frame.
    */
   public void update(float tpf) {
      input.update(tpf);
   }

   /**
    * Should be initialized by derived classes.
    * @see GameState.update(float)
    */
   public void cleanup() {

   }
   
   /**
    * Gets the camera of this state.
    * @return The camera of this state.
    */
   public Camera getCamera() {
      return cam;
   }
   
   /**
    * Gets the state node of this state.
    * @return The state node of this state.
    */
   public Node getStateNode() {
      return stateNode;
   }
   
   /**
    * Initializes a standard camera.
    */
   private void initCamera() {
      DisplaySystem display = DisplaySystem.getDisplaySystem();
      
      cam = display.getRenderer().createCamera(
            display.getWidth(),
            display.getHeight());
      
      cam.setFrustumPerspective(45.0f,
            (float) display.getWidth() /
            (float) display.getHeight(), 1, 1000);
      
      cam.update();
   }

   /**
    * Initialize the input handler.
    */
   protected abstract void initInput();
}


import java.util.Hashtable;
import java.util.logging.Level;

import com.jme.scene.Node;
import com.jme.system.DisplaySystem;
import com.jme.util.LoggingSystem;

/**
 * A manager to handle multiple game states. The game states are binded to
 * strings that function as keys. Only the active game state gets updated.
 * Use switchTo(String) to switch the active game state.
 *
 * @author Per Thulin
 */
public class GameStateManager {
   
   // The singleton.
   private static GameStateManager instance;
   
   // The hashtable that will store all our game states.
   private Hashtable states;
   
   // The active game state.
   private GameState current;
   
   // The root of the scenegraph.
   private Node rootNode;
   
   /**
    * Private constructor.
    * @param rootNode The root of the scene graph.
    */
   private GameStateManager(Node rootNode) {
      this.rootNode = rootNode;
      states = new Hashtable(0, 1.0f);
   }
   
   /**
    * Creates a new <code>GameStateManager</code> connected to the passed
    * rootNode.
    * @param rootNode The root of the scene graph.
    * @return If this is the first time create() is called, a new instance
    * will be created and returned. Otherwise one should use getInstance()
    * instead.
    */
   public static GameStateManager create(Node rootNode) {
      if (instance == null) {
         instance = new GameStateManager(rootNode);
         LoggingSystem.getLogger().log(Level.INFO, "Created GameStateManager");
      }
      return instance;
   }
   
   /**
    * Returns the singleton instance of this class. Note that create() has to
    * have been called before this.
    * @return The singleton.
    */
   public static GameStateManager getInstance() {
      return instance;
   }
   
   /**
    * Binds a name/key to a <GameState>. Note that this doesn't make the
    * passed game state the active one. In order for that, you'd have to call
    * switchTo(String).
    * @param name The name/key of the Game State to add.
    * @param state The <code>GameState</code> to bind to the passed name.
    */
   public void addGameState(String name, GameState state) {
      states.put(name, state);
   }
   
   /**
    * Removes a <code>GameState</code>, meaning that we call its cleanup() and
    * removes it from the hashtable.
    * @param name The name/key of the Game State to remove.
    */
   public void removeGameState(String name) {
      GameState state = (GameState) states.get(name);
      state.cleanup();
      states.remove(name);
   }
   
   /**
    * Switches to a <code>GameState</code>, meaning that we detatch the active
    * states stateNode and attaches the new ones instead. We also
    * set the new states <code>Camera</code> to our <code>Renderer</code>.
    * @param name The name/key of the Game State to switch to.
    */
   public void switchTo(String name) {
      rootNode.detachAllChildren();

      current = (GameState)states.get(name);
      rootNode.attachChild(current.getStateNode());

      DisplaySystem.getDisplaySystem().getRenderer().
         setCamera(current.getCamera());

      rootNode.updateRenderState();
      rootNode.updateGeometricState(0, true);
   }
   
   /**
    * Updates the current/active game state.
    * @param tpf The time since last frame.
    */
   public void update(float tpf) {
      if (current != null) {
         current.update(tpf);
      }
   }
}



What do you guys think?

/Per

Looks good to me. There are two things I’d like to suggest though:


  1. may adding a sound root node would allow switching sounds, too? I’m not very familiar with the sound api yet, but it should be part of the state engine.


  2. I found it very useful to have "call" and "return" in my state manager, as this allows to place e.g. an "options" in the main menu and in the game itself. It may enforce reusability of states.

You need a render method. There some cases in which you cant only use one root node such as drawing bounds or rendering to textures.

"batman.ac" wrote:
1. may adding a sound root node would allow switching sounds, too? I'm not very familiar with the sound api yet, but it should be part of the state engine.
Well, if using the SoundManager (you can find it under another thread in this section) you would load the sounds needed in init of each state, and during cleanup remove them. However I've added this to GameStateManager.switchTo(GameState):

if (SoundAPIController.getRenderer() != null)
   SoundAPIController.getRenderer().setCamera(current.getCamera());


"batman.ac" wrote:
2. I found it very useful to have "call" and "return" in my state manager, as this allows to place e.g. an "options" in the main menu and in the game itself. It may enforce reusability of states.
I'm not following :?
"Badmi" wrote:
You need a render method. There some cases in which you cant only use one root node such as drawing bounds or rendering to textures.
Hmm, true. Should the stateNode still be attached to the rootNode? Or should the stateNode be the rootNode?

just a little remark,



i thought i read somewhere that sun recommand using hashmap instead of hashtable (if i have not forgot what they say, the implementation of the hashcode is better with hashmap than with hashtable). Have you read something similar on this ?



bye,



Adenthar

"adenthar" wrote:
Have you read something similar on this ?
No I havn't, but doc says the difference is that HashMap is unsynchronized, which is good since we only expect users to be running one thread, right? So I went on and changed it :)
"Per" wrote:
"batman.ac" wrote:
2. I found it very useful to have "call" and "return" in my state manager, as this allows to place e.g. an "options" in the main menu and in the game itself. It may enforce reusability of states.
I'm not following :?

Look here:

http://www.mojomonkeycoding.com/jmeforum/viewtopic.php?t=484

Sadly the image is missing now, but the basic idea should still be clear. Especially the points about delegation and switching.

Aah, you mean return like in return to last game state? What would ‘call’ be then?



I think that ingame-menus/pause-screens etc. is out of the GameStateManager defenition boundarys (it would require GameStateManager to update & render two states). Instead I think the GameStates themselves should handle it, like:

GameState.update() {

    if pause button is pressed {

        do nothing but listen for another pause button press

    } else {

        do game stuff

    }

}





About the render thing, do you guys have anything against that the stateNodes become rootNodes, and letting each state have it’s own render(float interpolation)? StandardGameState would then apply a default ZBufferState to its rootNode (like done in SimpleGame), and its render() would just draw the rootNode.

"Per" wrote:
Hmm, true. Should the stateNode still be attached to the rootNode? Or should the stateNode be the rootNode?

I say attached. This would allow you to have something like a sky box that all the sates should have.

Ok, leaving things as they are, and just adding the render method.

I’m gonna add a switchTo() method to GameState which in turn will get called by GameStateManager.switchTo(String). It’s because sometimes there are procedures you want to execute everytime you enter a game state.

Per, are you ready to submit this to the base line? If so, post the latest one for comments. Seeing it work in Marble Fun leads me to believe it is ready to go.

I was hoping to integrate this into the GameSystem (infact, ive already done so). So that it, the entity system, entity, entityActions, entityEvents can go in at the same time.



Or do people not prefer that?



DP