AbstractAppState::initialize vs AbstractAppState::stateAttached

I am using the following code



In the state :

[java]public class InGameState extends AbstractAppState implements ScreenController {



SimpleApplication game = null;



// **** Test LeveL

TestLevel testLevel;



public InGameState(SimpleApplication game) {

this.game = game;

}



@Override

public void initialize(AppStateManager stateManager, Application app) {

super.initialize(stateManager, app);



game.getInputManager().setCursorVisible(false);

}



@Override

public void stateAttached(AppStateManager stateManager) {

// ***** Test Level Initialization *****

testLevel = new TestLevel(game);

testLevel.Initialize();

}



@Override

public void stateDetached(AppStateManager stateManager) {

}



@Override

public void update(float tpf) {

super.update(tpf);



// ***** Test Level Update ***

testLevel.update(tpf);



}



public void bind(Nifty nifty, Screen screen) {

}



public void onStartScreen() {

}



public void onEndScreen() {

}

}

[/java]



the lines just below the //
are the level class specific code. If I put them

[java] testLevel = new TestLevel(game);

testLevel.Initialize(); [/java] to AbstractAppState::Initialize() , I get error. But this way it runs fine.



the TestLevel class like following,

[java]public class TestLevel {

private SimpleApplication game;

private AssetManager assetManager;

private Node rootNode;

private Node guiNode;

private ViewPort viewPort;

private ViewPort guiViewPort;

private FilterPostProcessor filterProcessor;



public TestLevel(SimpleApplication game){

this.game = game;

this.rootNode = game.getRootNode();

this.guiNode = game.getGuiNode();

this.assetManager = game.getAssetManager();

this.viewPort = game.getViewPort();

this.guiViewPort = game.getGuiViewPort();

this.filterProcessor = new FilterPostProcessor(assetManager);

}



public void Initialize(){

// Here I add my assets to the rootNode

}



public void update(float tpf){

// Update loop

}

}[/java]



So, where do you think I am doing wrong?



( I will use your class some time later. Im trying to use the AppState Class for now.)

Is your application based on SimpleApplication? Where do you attach the InGameState?

Yes, it extends SimpleApp.

And you only override simpleUpdate() and not update()?



See, the thing is, the code is pretty simple in this area.



Attach state:

calls stateAttached



update()

calls state.initialize

calls state.update

runs simpleUpdate



It cannot be otherwise unless you’ve somehow changed the behavior of SimpleApplication or are somehow calling your app state’s initialize from somewhere else.



So in the end I don’t really have enough to help further. In a normal application, things will work fine… I don’t know what’s different about your case.

I am overriding simpleUpdate() and I am not actually doing anything there. The main class very simple,



[java]public class GameMain extends SimpleApplication{



private static GameMain game = null;

private MainMenuState mainMenuState;

private BulletAppState bulletAppState;

float GameMainTpf;



public static GameMain getInstance(){

return game;

}



public static void main(String[] args){

game = new GameMain();

game.setShowSettings(false);



AppSettings newAppSettings = new AppSettings(true);

newAppSettings.setResolution(640, 480);

//newAppSettings.setBitsPerPixel(32);

newAppSettings.setTitle(“Rabbit’s Fury - Framework v0.2”);

//newAppSettings.setVSync(true);

//newAppSettings.setSamples(4);

newAppSettings.setFullscreen(false);

// newAppSettings.setSettingsDialogImage("/splash_all.jpg");

game.setSettings(newAppSettings);

game.start();

}



public void simpleInitApp() {

fixSimpleApp();



bulletAppState = new BulletAppState();

mainMenuState = new MainMenuState(this);



stateManager.attach(bulletAppState);

stateManager.attach(mainMenuState);

}



@Override

public void simpleUpdate(float tpf){

GameMainTpf = tpf;

}



public PhysicsSpace getPhysicsSpace(){

return bulletAppState.getPhysicsSpace();

}



public float getTpf(){

return GameMainTpf;

}



public void fixSimpleApp(){

// flyCam.setEnabled(false);

// inputManager.deleteMapping(INPUT_MAPPING_EXIT);

}

}[/java]



When I press Start game button, MainMenuState detach itself, and it also attachs InGameState to the statemanager.

All of that looks fine.



Even, I bet if you put a System.out.println() in simpleUpdate() and another one in your InGameState.initialize() (and put your test level stuff back in initialize) that you will see the one in initialize before the one in simpleUpdate(). Which means it has to be something else… since clearly you’d be able to modify the scene graph in simpleUpdate().



Do you do anything strange in TestLevel.Initialize()?



Alternately, you could try creating a new separate fresh empty application project… just for testing this. Add a test app state and add something to rootNode in the test app state’s initialize just to prove to yourself it works. Then you just need to figure out what about your application is making it not work right.

No, i am not doing anything strage in TestLevel.Initialize. In fact, i tried the most simple blue cube program(attaching a blue cube to the rootNode)



& I ve tested with an simple test app, and it works fine as you said so.



I have cornered the issue a little more. It something related to my MainMenuState. If I start plugin my MainMenuState before InGameState, that problem occurs.(that problem : I’ve to put my code in stateAttach()). But if i launch my InGameState bypassing MainMenuState, its just fine.(I can put my code in the Initialize method)



MainMenuState Code is following

[java]public class MainMenuState extends AbstractAppState implements ScreenController{



SimpleApplication game = null;

private NiftyJmeDisplay niftyDisplay = null;

private Nifty nifty = null;



public MainMenuState(SimpleApplication game) {

this.game = game;

}



@Override

public void initialize(AppStateManager stateManager, Application app) {

super.initialize(stateManager, app);



niftyDisplay = new NiftyJmeDisplay(game.getAssetManager(),

game.getInputManager(),

game.getAudioRenderer(),

game.getGuiViewPort());

nifty = niftyDisplay.getNifty();



nifty.fromXml(“Interface/intro.xml”, “start”, this);



game.getGuiViewPort().addProcessor(niftyDisplay);

game.getInputManager().setCursorVisible(true);

}



@Override

public void stateAttached(AppStateManager stateManager) {

}



@Override

public void stateDetached(AppStateManager stateManager) {

game.getGuiViewPort().removeProcessor(niftyDisplay);

game.getRootNode().detachAllChildren();

game.getGuiNode().detachAllChildren();

game.getStateManager().attach(new InGameState(game));

}



@Override

public void update(float tpf) {

super.update(tpf);

if (nifty.getScreen(“start”) == null) game.getStateManager().detach(this);

}



public void bind(Nifty nifty, Screen screen) {

}



public void onStartScreen() {

}



public void onEndScreen() {

}



public void startGame(){

nifty.removeScreen(“start”);

}



public void exitGame(){

game.stop();

}

}

[/java]



Very simple. I don’t find anything suspicious here. But, something in the code is causing the issue. What do you suggest?

Ugh, this is because of a bug in AppStateManager with its loose handling of state life cycle. As it stands, if you add an AppState in update then it gets initialized in render… too late to make any scene graph mods.



The reason I don’t hit this is because I’m attaching my new states as the result of a nifty event which comes in before the state manager update pass.



I’m going to try to fix AppStateManager in the next few days. And we’ll also finally be free of the “why is initialize called more than once?” style issues.

1 Like

whew! Everytime I hit a bug in jME, it feels I am not as dumb as i think :stuck_out_tongue:


if you add an AppState in update then it gets initialized in render… too late to make any scene graph mods.

ah, sorry I dont really get it. Can you please clarify it a little more.

another thing is, how do you know the Nifty event is going to be triggered before the update of the appstate?

AppStateManager is called by the render thread several times per frame. update, render, and postRender. Each of those runs through all of the app states and calls their update, render, and postRender methods… and will call initialize first (in each of those cases) if isInitialized() returns false. (So actually, initialize can be called three times per frame!!!) Anyway, if you attach a new AppState in update() then it will be in the list for render()… and get initialized in render()… and you can’t modify the scene graph there. It’s very bad.



I know what nifty is called first because it’s part of InputManager processing which happens before AppStateManager.update(). Input events process first in this case.

I have performed semi-major surgery on the internals of AppStateManager to prevent these issues and hopefully deliver a more consistent app state life cycle. It’s in SVN and with luck will make it into one of the stable updates soon.

Thanks that was fast. I will report back when I’ve got the update.


Anyway, if you attach a new AppState in update() then it will be in the list for render()… and get initialized in render()… and you can’t modify the scene graph there. It’s very bad.


Now, can I detach & attach a state form the state update? what will happen after this fix?

Yes. After this fix things will behave as expected. If you attach a state it will always get initialized at the beginning of the next update loop… regardless of where or when you attached it.