About change gamestate back async process

Hello!



Today thinking about develop an system i found a problem implement it…



I have one GameStateNode and some childs, the childs ever running independent of other childs.

I want that when active a GameState this start a fadeIn elements (Controller) and WHEN FINISH call to one callback, in case of fadeIn the cb is setupInputs() in case of fadeout (When we try desactive the state) the cb is deactivechildnamed…



MenuStat


  • IntroMenuState

  • MainMenuState

  • CreditsMenuState



My current implementation is aprox this..

In MenuState i implement a common quad, as an wood background.
i want implement that when the state START and FINNISH (active-deactive) the Geoms of the state run a FadeIn or FadeOut effect AND WHEN FADE FINISH call a method for change state (finish-case) o buildinputs events (start-case).

Then i think about implement this system:
* reimplement the setActive of each child state for DONT call the super, only assign the new GameState to this.queuedGameState attr and later call this.fadeIn() method for run controllers.
* Later in MenuState (GameStateNode) update() i check if exist fades-controllers running, and if not, look the this.queuedGameState string value for check if is same that the current active child, if is same i can confirm that the FadeIn just finish, or if this.queuedGameState is diferent string and i dont have fade controllers running, i assume that  fadeOut just finish and then call the true activechild() (super)

I think that my system is tooo complex (And hardy of understand yes..) ... really i dont like, i want know if you think other way for implement better this?


Thanks for read this ugly post :P

Of course!



I Upload my src dir.

http://dl.getdropbox.com/u/663461/TransitionGameStateDemo.zip



Run the game and you can see how run BAD (super fast i think) the first fade.


no, I mean a single class…



It can take anywhere from 5-15 mins to setup a project like that to run here, a single class can be copy and pasted in a matter of seconds.  (that really adds up when there are so many posts a day…)



It should only take around 100-200 lines to represent any problem (any more than that and the problem should be narrowed down some more)…



This is for your benefit also, I can't count the number of times I have solved my own issues by creating a simple test case.

This is for your benefit also, I can't count the number of times I have solved my own issues by creating a simple test case.


We call this a "cardboard cutout moment" in my office. One of the guys I used to work with had a small teddy bear sat next to his monitor. Sometimes when he got stuck on a problem, he tried to explain the problem to the bear (yup - barking mad I know) - but often in the case of trying to explain it clearly the solution came.

We didn't want to call this the "taking to a stuffed toy moment", so came up with a slightly less embarasing name :D

Here the one-file code.



import java.net.URL;

import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.shape.Quad;
import com.jme.util.Timer;
import com.jmex.game.StandardGame;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.GameStateManager;
import com.jmex.game.state.load.TransitionGameState;


public class GameStateTest {

   private static StandardGame game;
   
   public static void main(String[] args) {

      
       /*
        * FIRST GAME STATE
        */
       class MyFirstGameState extends BasicGameState {

           private boolean mark;

           public MyFirstGameState() {
          super("MyFirstGameState");
          this.rootNode.setRenderQueueMode(Renderer.QUEUE_ORTHO);   
          
          Quad topQuad = new Quad("firstQuad", 400, 200);
          topQuad.setLocalTranslation(200, 100, 1);
          topQuad.setSolidColor(new ColorRGBA(1f, 0f, 0f, 1f));
          this.getRootNode().attachChild(topQuad);
          
          this.rootNode.updateRenderState();
           }
          
           private void createTransition() {
          // Create TransitionGameState
          URL url = MyFirstGameState.class.getClassLoader().getResource("res/woodBckg.png");
          TransitionGameState transition = new TransitionGameState(this, url);
          GameStateManager.getInstance().attachChild(transition); // Attach
          transition.setActive(true); // Active it
          transition.setProgress(0f, "");
          GameStateManager.getInstance().activateChildNamed("MySecondGameState"); // Attach
          transition.setProgress(1f, "");
           }
          
           public void update(float tpf) {
              super.update(tpf);
              Timer timer = Timer.getTimer();
              if (timer.getTimeInSeconds() > 5f) {
                  if (!this.mark) {
                 this.mark = true;
                 this.createTransition();
                  }

              }
           }
       }      
      
      
      
       class MySecondGameState extends BasicGameState {

          public MySecondGameState() {
         super("MySecondGameState");
         this.getRootNode().setRenderQueueMode(Renderer.QUEUE_ORTHO);   
         
         Quad topQuad = new Quad("secondQuad", 400, 200);
         topQuad.setLocalTranslation(200, 100, 1);
         topQuad.setSolidColor(new ColorRGBA(0f, 0f, 1f, 1f));
         this.getRootNode().attachChild(topQuad);
         
         this.getRootNode().updateRenderState();   
          }   
         
      }
      
      
      
       /*
        *  LAUNCH THE GAME
        */
          GameStateTest.game = new StandardGame("StandardGame");
          GameStateTest.game.getSettings().setWidth(400);
          GameStateTest.game.getSettings().setHeight(200);
          
          // START HACK SOUND
          GameStateTest.game.getSettings().setVerticalSync(false);
          GameStateTest.game.getSettings().setMusic(false);
          GameStateTest.game.getSettings().setSFX(false);
          // END HACK SOUND
          
          GameStateTest.game.start();
          GameStateTest.game.getDisplay().setTitle("jMe Test Area");
          
          //GameStateManager.getInstance().attachChild(new MyGameStateNode());
          GameStateManager.getInstance().attachChild(new MyFirstGameState());
          GameStateManager.getInstance().attachChild(new MySecondGameState());
          GameStateManager.getInstance().activateChildNamed("MyFirstGameState");
      
   }
   
}



This code require this image: (res/woodBckg.png)
http://dl.getdropbox.com/u/663461/woodBckg.png

did you try to use TransitionGameState yet ?

I read about transitionGameState but dont fix my problem. (no? im not sure)



I try make a fade alpha of all elements in current BasicGameState, and later finish the fade, call the deactive and active for change to the next gamestate.



this its possible with TransitionGameState?



Now in my code im using this code for when active the state:


   public void setActive(boolean value) {
      if (value) {
           // Fade and setup inputs
           this.fadeAll(true, 0.7f, new Callable<Object>() {
            @Override
            public Object call() throws Exception {
               // TODO: Active inputs here
               return null;
            }
           });
      }
        super.setActive(value);
   }




And this other for when go out in key events.

this.fadeAll(false, 0.7f, new Callable<Object>() {
                  @Override
                  public Object call() throws Exception {
                     parentGameState.deactivateChildNamed("MainMenuState");
                     parentGameState.activateChildNamed("CreditsMenuState");
                     return null;
                  }
                 })




My this.fadeAll method, launch a LifedTimeController and iter over each Geom for change getDefaultColor.a attr.
Now i need implement this method new in each state. Exist the chance of change alpha of ALL gamestate.?

Update: I want make this fade effect! im doing this now with the previus code. (Its better and possible use TransitionGameState?)

VIDEO DEMO: http://www.youtube.com/watch?v=9KWeii4zMVQ

I try use TransitionGameState,  with the same background image of the other gamestates background, then i think that can run fine… but…



TransitionGameState dont work fine because the "first fade" dont show the fade, jump directly to TransitionGameState image opaque and later start fadin out good.



Here i post the two gamestates the first and the second, in first GameState (update()) i launch the transition.





MyFirstGameState.java

public class MyFirstGameState extends BasicGameState {

    private boolean mark;

    public MyFirstGameState() {
   super("MyFirstGameState");
   this.rootNode.setRenderQueueMode(Renderer.QUEUE_ORTHO);   
   Quad topQuad = new Quad("firstQuad", 400, 200);
   topQuad.setLocalTranslation(200, 100, 1);
   topQuad.setSolidColor(new ColorRGBA(1f, 0f, 0f, 1f));
   this.getRootNode().attachChild(topQuad);
   this.rootNode.updateRenderState();
    }
   
    private void createTransition() {
   // Create TransitionGameState
   URL url = MyFirstGameState.class.getClassLoader().getResource("res/woodBckg.png");
   TransitionGameState transition = new TransitionGameState(this, url);
   GameStateManager.getInstance().attachChild(transition); // Attach
   transition.setActive(true); // Active it
   transition.setProgress(0f, "");
   // Activate the BasicGameState that before attach
   GameStateManager.getInstance().activateChildNamed("MySecondGameState");
   transition.setProgress(1f, "");
    }
   
    public void update(float tpf) {
   super.update(tpf);
   Timer timer = Timer.getTimer();
   if (timer.getTimeInSeconds() > 5f) {
       if (!this.mark) {
      this.mark = true;
      this.createTransition();
       }
   }}}




MySecondGameState.java

public class MySecondGameState extends BasicGameState {

    public MySecondGameState() {
   super("MySecondGameState");
   this.getRootNode().setRenderQueueMode(Renderer.QUEUE_ORTHO);   
   Quad topQuad = new Quad("secondQuad", 400, 200);
   topQuad.setLocalTranslation(200, 100, 1);
   topQuad.setSolidColor(new ColorRGBA(0f, 0f, 1f, 1f));
   this.getRootNode().attachChild(topQuad);
   this.getRootNode().updateRenderState();   
    }}

Anyway you can whip that up into a small test (self contained, using internal classes) that someone (like myself) can just copy/paste and run?  (I am no understanding the issue at hand…)

Perfect :slight_smile:



In this case it is the order in which you are adding the states  (the second state needs to be added first, otherwise when activated the first game state fades out 'underneath' it…)



I have altered your test (and created a 'fade-in/fade-out' transition for you).



package Tests;

import java.net.URL;

import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.shape.Quad;
import com.jme.util.Timer;
import com.jmex.game.StandardGame;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.GameState;
import com.jmex.game.state.GameStateManager;
import com.jmex.scene.TimedLifeController;
import com.tribaling.tildruin.shared.util.Utils;



public class GameStateTest {

    private final StandardGame game;
    //

    public static void main( String[] args ) {
        new GameStateTest();

    }

    private GameStateTest() {
        game = new StandardGame( "StandardGame" );
        game.getSettings().setWidth( 400 );
        game.getSettings().setHeight( 200 );

        // START HACK SOUND
        game.getSettings().setVerticalSync( false );
        game.getSettings().setMusic( false );
        game.getSettings().setSFX( false );
        // END HACK SOUND

        game.start();
        game.getDisplay().setTitle( "jMe Test Area" );

        final MyFirstGameState firstState = new MyFirstGameState();

        GameStateManager.getInstance().attachChild( new MySecondGameState() );
        GameStateManager.getInstance().attachChild( firstState );
        GameStateManager.getInstance().attachChild( createTransition( firstState ) );

        GameStateManager.getInstance().activateChildNamed( "MyFirstGameState" );
    }

    private TransitionGameState createTransition( final BasicGameState leadIn ) {

        URL url = Utils.getURL( "textures/characters/high/villager/Beard_00X.png" );
        final TransitionGameState transition = new TransitionGameState( leadIn, url );
        transition.setName( "TransitionGameState" );
        GameStateManager.getInstance().attachChild( transition ); // Attach
        transition.setActive( false );
        transition.setProgress( 0f, "" );

        return transition;
    }

    private void activateTransition() {
        GameStateManager.getInstance().activateChildNamed( "TransitionGameState" );
        GameStateManager.getInstance().activateChildNamed( "MySecondGameState" );
    }



    class TransitionGameState extends com.jmex.game.state.load.TransitionGameState {

        final GameState leadIn;

        private TransitionGameState( GameState leadIn, URL imagePath ) {
            super( leadIn, imagePath );

            this.leadIn = leadIn;

            final TransitionFader fader = new TransitionFader( 2.0f );  // 2 seconds
            rootNode.addController( fader );
            fader.setActive( true );
        }

        public void update( float tpf ) {
            if( !isActive() ){
                return;     // Don't update Controller
            }
            rootNode.updateGeometricState( tpf, true );
        }



        class TransitionFader extends TimedLifeController {

            private boolean fadingOut = false;

            public TransitionFader( float lifeInSeconds ) {
                super( lifeInSeconds );
            }

            public void updatePercentage( float percentComplete ) {

                if( fadingOut ){
                    TransitionGameState.this.setAlpha( (1 - percentComplete) * 2 );
                } else{
                    TransitionGameState.this.setAlpha( percentComplete * 2 );
                }

                if( percentComplete >= 0.5f && !fadingOut ){
                    TransitionGameState.this.leadIn.setActive( false );
                    fadingOut = true;
                } else if( fadingOut && percentComplete == 1.0f ){
                    this.setActive( false );
                }
            }
        }
    }



    class MySecondGameState extends BasicGameState {

        public MySecondGameState() {
            super( "MySecondGameState" );
            this.getRootNode().setRenderQueueMode( Renderer.QUEUE_ORTHO );

            Quad topQuad = new Quad( "secondQuad", 400, 200 );
            topQuad.setLocalTranslation( 200, 100, 1 );
            topQuad.setSolidColor( new ColorRGBA( 0f, 0f, 1f, 1f ) );
            this.getRootNode().attachChild( topQuad );

            this.getRootNode().updateRenderState();
        }
    }



    class MyFirstGameState extends BasicGameState {

        private boolean mark;

        public MyFirstGameState() {
            super( "MyFirstGameState" );
            this.rootNode.setRenderQueueMode( Renderer.QUEUE_ORTHO );

            Quad topQuad = new Quad( "firstQuad", 400, 200 );
            topQuad.setLocalTranslation( 200, 100, 1 );
            topQuad.setSolidColor( new ColorRGBA( 1f, 0f, 0f, 1f ) );
            this.getRootNode().attachChild( topQuad );

            this.rootNode.updateRenderState();
        }

        public void update( float tpf ) {
            super.update( tpf );
            Timer timer = Timer.getTimer();
            if( timer.getTimeInSeconds() > 5f ){
                if( !this.mark ){
                    this.mark = true;
                    activateTransition();
                }

            }
        }
    }
}

But for why create a new Transition class?  the javadoc say:



TransitionGameState The transition game state provides additional functionality to LoadingGameState. A background image is now shown during the loading phase of LoadingGameState. In addition, if a lead in game state is provided, the transition state will fade frame the previous game state into the loading state and then fade away. The lead in game state will be deactivated once the transition is complete, but not removed from the game state manager.



Then… TransitionGameState make fadein-fadeout feature, out of box, no?

Sorry, didn't even read the javadoc



The problem is that you are never updating the progress, when the progress gets to 1.0 (through the setProgress() method) it triggers the fade out (not sure that's appropriate)…



here is a 'hack' that should work for you



import java.net.URL;

import com.jme.renderer.ColorRGBA;
import com.jme.renderer.Renderer;
import com.jme.scene.shape.Quad;
import com.jme.util.Timer;
import com.jmex.game.StandardGame;
import com.jmex.game.state.BasicGameState;
import com.jmex.game.state.GameState;
import com.jmex.game.state.GameStateManager;
import com.tribaling.tildruin.shared.util.Utils;



public class GameStateTest {

    private final StandardGame game;
    //

    public static void main( String[] args ) {
        new GameStateTest();
    }

    private GameStateTest() {
        game = new StandardGame( "StandardGame" );
        game.getSettings().setWidth( 400 );
        game.getSettings().setHeight( 200 );

        // START HACK SOUND
        game.getSettings().setVerticalSync( false );
        game.getSettings().setMusic( false );
        game.getSettings().setSFX( false );
        // END HACK SOUND

        game.start();
        game.getDisplay().setTitle( "jMe Test Area" );

        GameStateManager.getInstance().attachChild( new MySecondGameState() );
        GameStateManager.getInstance().attachChild( new MyFirstGameState() );

        GameStateManager.getInstance().activateChildNamed( "MyFirstGameState" );
    }

    private void activateTransition( final BasicGameState leadIn ) {

        URL url = Utils.getURL( "textures/characters/high/villager/Beard_00X.png" );
        final TransitionGameState transition = new TransitionGameState( leadIn, url );
        transition.setName( "TransitionGameState" );
        GameStateManager.getInstance().attachChild( transition ); // Attach
        transition.setActive( false );
        transition.setProgress( 0f, "" );

        GameStateManager.getInstance().activateChildNamed( "TransitionGameState" );
        GameStateManager.getInstance().activateChildNamed( "MySecondGameState" );
    }



    class TransitionGameState extends com.jmex.game.state.load.TransitionGameState {
       
        private TransitionGameState( GameState leadIn, URL imagePath ) {
            super( leadIn, imagePath );
        }
       
        @Override
        public void update( float tpf ) {
            super.update( tpf );
            if ( color.a == 1.0f ) {
                this.setProgress( 1.0f );  // Trigger the fade out
            }
        }
    }



    class MySecondGameState extends BasicGameState {

        public MySecondGameState() {
            super( "MySecondGameState" );
            this.getRootNode().setRenderQueueMode( Renderer.QUEUE_ORTHO );

            Quad topQuad = new Quad( "secondQuad", 400, 200 );
            topQuad.setLocalTranslation( 200, 100, 1 );
            topQuad.setSolidColor( new ColorRGBA( 0f, 0f, 1f, 1f ) );
            this.getRootNode().attachChild( topQuad );

            this.getRootNode().updateRenderState();
        }
    }



    class MyFirstGameState extends BasicGameState {

        private boolean mark;

        public MyFirstGameState() {
            super( "MyFirstGameState" );
            this.rootNode.setRenderQueueMode( Renderer.QUEUE_ORTHO );

            Quad topQuad = new Quad( "firstQuad", 400, 200 );
            topQuad.setLocalTranslation( 200, 100, 1 );
            topQuad.setSolidColor( new ColorRGBA( 1f, 0f, 0f, 1f ) );
            this.getRootNode().attachChild( topQuad );

            this.rootNode.updateRenderState();
        }

        @Override
        public void update( float tpf ) {
            super.update( tpf );
            Timer timer = Timer.getTimer();
            if( timer.getTimeInSeconds() > 5f ){
                if( !this.mark ){
                    this.mark = true;
                    activateTransition( this );
                }

            }
        }
    }
}



Im updating the progress, i set to 0, (i think that must start fadeIN) later active the wood image, and later set to 1, (fadeout trigger)



Your example run fine, but one thing more, Can i disable the text? i dont want any text.



Maybe is better create my own transitionGameState.