GameStateNode tree understanding

thats kind weird… a server game state and client game state as siblings?



the tree structure should look something like this:



LoginGameState (Where u enter username and password)

    - MainMenuState

    - LoginGUIState



WorldGameState (The general world)

    - MenuState (Press ESC to bring up this)

    - WorldGUIState (Press something like atl+z to disable this. this should be rendered into a different pass)

Just using http://www.jmonkeyengine.com/wiki/doku.php?id=some_standardgame_frequently_asked_questions#can_you_give_me_another_real-life_example_of_gamestate_use as the example.



but is the code itself how it should look, regardless if this gamestate should be a child of that gamestate or not?



BTW. Could I have the MenuState as a child of both the worldstate and loginstate?

foobar said:

Just using http://www.jmonkeyengine.com/wiki/doku.php?id=some_standardgame_frequently_asked_questions#can_you_give_me_another_real-life_example_of_gamestate_use as the example.

but is the code itself how it should look, regardless if this gamestate should be a child of that gamestate or not?

BTW. Could I have the MenuState as a child of both the worldstate and loginstate?


i dont know who wrote that wiki, but it seems very odd to me. it seems like that example is running both client and server code on the same machine in the same vm.... and that is just very very odd.

the game state concept is not very complicated. it basically gives u a way to group things together and allows u turn off the things u dont need to use easily. thinking about coding everything under the same method (like initizlieGame()) is just too messy and hard to manage. however, using game states allows u to separate all these objects into logical stages of the game. like the game logo u wanna show in the login state of an mmo is not shown in the world state where players exploring the world. and it is logical to put that logo initialization into the login state.

also, maintaining children states allow u to further group things in the convinient way. such as a menu state. all the gui stuff doesnt need to be initialzied and displayed all the time during the world state, and if u put them inside a child gui state, u can easily turn that state on and off in response to user inputs. and since it is a child of the world state, once u turn off the world state, it automatically turns off the gui state as well.

I didn't write the wiki, but I believe that paragraphs are copied from one of my posts.



I still think is a perfectly reasonable way of organising gamestates, but that example is for a client/server game where server runs in the same process than a client (like a FPS where you start a server and then other players can connect to your game). But it also works for dedicated servers or for standalone clients (with movement prediction).



I think it is not a good example anyway, and maybe my management of Input is weird given current jME possibilities to handle input. I don't think it should have been made a Wiki entry.



I still don't know the best way to structure a game regarding GameStates, I was just commenting my solution in that post.



Regards,

I guess I'm more or less wondering about if the code for trees using the nodes is right the idea on how to use the GameStateNodes.



I just used that example because it was defined already in the wiki. Assume I was to use that regardless of any other structure suggested (not that I will, but for example purposes I will) is the code correct? By making the tree as shown out of the GameStateNodes and then simply attaching the Necessary GameStates to each of the appropriate nodes.

It looks perfectly correct to me.



You will probably want to disable some gamestates or nodes at creation time, so not all of them are active from startup.

even if the game itself is a FPS game like the one u described, i still dont c any reason y u would want to put the server anc client in the same vm.



but using a tree structure for ur game state is absolutely correct.

About the client and server on the same VM… I am not a networking expert but seems to me a reasonable way of implementing a dual server / client game.



The purpose is to start the server without spawning another process, so the rootNode and the PhysicsSpace of the level are shared, as are all other entities and such.



With two VM, all those data would be duplicated and also calculations would happen twice, since the server process would need to calculate its own steps and the client VM would receive updates and would anyway have to calculate as well (movement prediction). This could be overcame but anywa if everything stays on the same VM is much easier and smoother, I think.



I am using the mentioned GameState structure and it also allows me seamlessly run a dedicated server (I do this disabling the client game state branch and running with DummyDisplaySystem).


the whole point of having a server is so that it can double check the calculations to prevent cheating. but anyways, we can talk about this topic some other time.

:?

Well I've replaced all gamestates and gamestatenodes with BasicGameStateNode because I couldn't figure out how to load models inside the gamestate.



Is there a section of the wiki or forums I'm missing on how to use GameStates? I tried searching the forums but it's hard to differentiate between working examples and ones that have issues. I'm rather weary on trying out examples from the forums that I've found to only find out a week later that it was the wrong way to do something. That's why I've prefered the wiki's examples as I'm hoping they are the proper methods to do things.



I'm at a complete loss now. I don't know what to do anymore. What I essentially need to know before I continue is actual code for putting a few boxes into several different gamestates and assuming gamestate.setActive(true) will switch between the two, I can then see what I've done so far. After that, I can play around with manipulating things. I can't even get started… here's all my code so you can point out all that i did wrong :wink: I left everything in, even old code so you can see where I was trying to go with what I've been doing. I originally was going for GameStates and GameStateNodes, but then switched to BasicGameStateNodes. I was also going to make a class for loading all the resources in another thread, which worked until i switched to trying out GameStates. It's commented out for now.



I'm just frustrated because I learn by examples and not by explainations.



gsLoginState.java

/*
 * gsLoginState.java
 *
 * Created on July 13, 2008, 11:12 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package pkgMain;

import com.jmex.game.state.GameState;
import com.jme.system.DisplaySystem;


// Temp Inlcudes

import com.jme.scene.shape.Box;
import com.jme.math.Vector3f;
import com.jme.bounding.BoundingBox;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.BasicGameStateNode;

/**
 *
 * @author Paul Warren
 */
public class gsLoginState extends BasicGameStateNode {
   
    static Box box;
   
    /** Creates a new instance of gsLoginState */
    public gsLoginState(String name) {
        super(name);
    }
 
    /**
     * Reset RenderStates before rendering FengGUI,
     * especially the TextureState.
     */
    @Override
    public void render(float tpf) {
        /*
        box = new Box("MyBox",
                          new Vector3f(),1.0f,1.0f,1.0f);
        box.setModelBound(new BoundingBox());
        box.setRandomColors();
        box.updateRenderState();
        rootNode.attachChild(box);
        rootNode.updateRenderState();
        */
    }
   
    /**
     * update the Inputhandler.
     */
    @Override
    public void update(float tpf) {

    }
   
    @Override
    public void cleanup() {
       
    }
   
}



tmpMain.java


/*
 * tmpMain.java
 *
 * Created on July 9, 2008, 11:06 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package pkgMain;

// import pkgResources.ResourceManager;
// GameStates:
//import pkgMain.gsMenuState;
import pkgMain.gsLoginState;

//import com.jme.app.AbstractGame;
//import com.jme.app.SimpleGame;
import com.jmex.game.StandardGame;
import com.jme.system.DisplaySystem;
import com.jmex.game.state.GameState;
import com.jmex.game.state.GameStateNode;
import com.jmex.game.state.GameStateManager;

import java.util.logging.Level;
import java.util.logging.Logger;


// TEMP
import com.jme.scene.state.LightState;
import com.jme.math.Vector3f;
import com.jme.renderer.ColorRGBA;
import com.jme.light.PointLight;
import com.jme.scene.shape.Box;
import com.jme.math.Vector3f;
import com.jme.bounding.BoundingBox;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.BasicGameStateNode;
/**
 *
 * @author Paul Warren
 */
public class tmpMain {
//    ResourceManager rmResources;
   
    /** Creates a new instance of tmpMain */
    public tmpMain () {
    }

    public static void main(String[] args) {
        tmpMain app = new tmpMain ();
        app.theGame(); // Start the program
    }
   
    public void theGame () {
        // TODO code application logic here
        StandardGame app = new StandardGame("game"); // Create Object
        // Signal to show properties dialog
        Logger.getLogger(tmpMain .class.getName()).setLevel(Level.OFF);
        app.start(); // Start the program
       
        /*
         * The structure of the rest of the nodes should be as follows:
         *  Main
         *      Server
         *      Client
         *          Input
         *          Render
         *              OOGame (out of game)
         *                  Login
         *                  MainMenu
         *                  *Disc Editor
         *                  *Store
         *                  *Other
         *              InGame
         *                  Menus
         *                      MainMenu (only faded background so the game can be seen in the back)
         *                      *Disc Editor
         *                      *Store
         *                      *Other
         *                  Level Renderer
         *              Console
         */

        // the main game state node
        GameStateNode gsn = new GameStateNode("gsMain");
       
        try {
//            this.rmResources = new ResourceManager();
//            rmResources.loadStage(1);

            // Setup the GameStateNodes.
            GameStateNode gsnClient = new GameStateNode("gsnClient");
            gsn.attachChild(gsnClient);
            GameStateNode gsnInput = new GameStateNode("gsnInput");
            gsnClient.attachChild(gsnInput);
            GameStateNode gsnRender = new GameStateNode("gsnRender");
            gsnClient.attachChild(gsnRender);
            GameStateNode gsnOOGame = new GameStateNode("gsnOOGame");
            gsnRender.attachChild(gsnOOGame);
            GameStateNode gsnInGame = new GameStateNode("gsnInGame");
            gsnRender.attachChild(gsnInGame);
            GameStateNode gsnConsole = new GameStateNode("gsnConsole");
            gsnRender.attachChild(gsnConsole);
            GameStateNode gsnOOMainMenu = new GameStateNode("gsnOOMainMenu");
            gsnOOGame.attachChild(gsnOOMainMenu);
            GameStateNode gsnLogin = new GameStateNode("gsnLogin");
            gsnOOGame.attachChild(gsnLogin);
            GameStateNode gsnMenus = new GameStateNode("gsnMenus");
            gsnInGame.attachChild(gsnMenus);
            GameStateNode gsnLevelRenderer = new GameStateNode("gsnLevelRenderer");
            gsnInGame.attachChild(gsnLevelRenderer);
            GameStateNode gsnIGMainMenu = new GameStateNode("gsnIGMainMenu");
            gsnMenus.attachChild(gsnIGMainMenu);
           
            // Common GameStateNodes
            GameStateNode gsnDiscEditor = new GameStateNode("gsnDiscEditor");
            GameStateNode gsnStore = new GameStateNode("gsnStore");
            GameStateNode gsnOther = new GameStateNode("gsnOther");
            gsnOOGame.attachChild(gsnDiscEditor);
            gsnOOGame.attachChild(gsnStore);
            gsnOOGame.attachChild(gsnOther);
            gsnIGMainMenu.attachChild(gsnDiscEditor);
            gsnIGMainMenu.attachChild(gsnStore);
            gsnIGMainMenu.attachChild(gsnOther);
           
            BasicGameState tasdfest = new BasicGameState("dfgh");
            BasicGameStateNode teasdfasd = new BasicGameStateNode("asdas");
            BasicGameStateNode asdfasdf = new BasicGameStateNode("asdfasd");
            asdfasdf.attachChild(teasdfasd);
            asdfasdf.attachChild(tasdfest);
           
           

           
            BasicGameStateNode gsLogin = new gsLoginState("gsLogin");
            gsn.attachChild(gsLogin);
            GameStateManager.getInstance().attachChild(gsLogin);
            gsLogin.setActive(true);
            gsLogin.getRootNode().updateRenderState();
           
            // START TEMP
            Box box = new Box("MyBox",
                              new Vector3f(),1.1f,1.1f,1.1f);
            box.setModelBound(new BoundingBox());
            box.setRandomColors();
            box.updateRenderState();
            gsLogin.getRootNode().attachChild(box);
           
            Box boxs = new Box("MyBoxs",
                              new Vector3f(),-1.1f,-1.1f,-1.1f);
            boxs.setModelBound(new BoundingBox());
            boxs.setRandomColors();
            boxs.updateRenderState();
            gsLogin.getRootNode().attachChild(boxs);
           
            PointLight lightPoint1 = new PointLight();
            lightPoint1.setLocation(new Vector3f(1, 1, 1));
            lightPoint1.setDiffuse(new ColorRGBA(.9f,.9f,1f,0.2f));
            lightPoint1.setSpecular(new ColorRGBA(1.0f, 1.0f, 1.0f, 0.2f));
            lightPoint1.setEnabled(true);
       
            LightState stateLights2 = DisplaySystem.getDisplaySystem().getRenderer().createLightState();
            stateLights2.attach(lightPoint1);
            gsLogin.getRootNode().setRenderState(stateLights2);
           
            gsLogin.getRootNode().updateRenderState();
            // END TEMP
           
            /*
            GameState gsMenu = new GameState();
            GameStateManager.getInstance().attachChild(gsMenu);
//            gsMenu.MakeMENU ( );
           
            rmResources.loadStage(2);
           
            GameState gsDeckEditor = new GameState();
            GameStateManager.getInstance().attachChild(gsDeckEditor);
//            gsDeckEditor.MakeDeckEditor ( );
            // Do this for each of the states EXCEPT for the actual game.
            // this is because the game must be made fresh every time it's connected to.
            */
        }catch(Exception e) {
           
        } 
    }
}



i never used GameStateNodes yet so i can't help you with that, i just create the GameStates i need, and activate / deactivate them when needed.


...only find out a week later that it was the wrong way to do something

i don't think there is a wrong or a correct way to do something, there are just many different ways to achieve something.
as long as it works ....  :)

I am the one who created that WiKi page and all the questions and answers there come either from the Forum, or tutorials in the WiKi. If you feel that it could use a better example for gamestate structure, please modify the WiKi accordingly, I am sure future users will appreciate this.



I collected those points when I started up with jME myself and was trying to understand StandardGame… so I read all threads on StandardGame I could get my hands on. Quite possible some points in there are out of date or not optimal. Unfortunately I do not boost sufficient knowledge myself to verify all of these answers myself.



But I believe as a Q&A it is still a good, more-or-less trustworthy, list that anyone interested of StandardGame could look through.