Problem with switching screens when using custom method (clicking start)

In my project, I am unable to switch to another ScreenState when I click a button. Using actionListeners, I don’t have this problem.

After clicking the Start Button, I switch to a new Nifty screen (“hud”). The corresponding AppState does, however, not change.

Here’s my code (in StartScreenState):
[java]
public StartScreenState startScreenState;
public RunningScreenState runningScreenState;
public StartScreenState(SimpleApplication app){
this.rootNode = app.getRootNode();
this.viewPort = app.getViewPort();
this.guiNode = app.getGuiNode();
this.assetManager = app.getAssetManager();

}

//Nifty GUI ScreenControl methods
public void bind(Nifty nifty, Screen screen) {
this.nifty = nifty;
this.screen = screen;
}

public void onStartScreen() { }

public void onEndScreen(){ }

@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
this.app=(SimpleApplication) app;
this.rootNode = this.app.getRootNode();
this.assetManager = this.app.getAssetManager();
this.stateManager = this.app.getStateManager();
this.inputManager = this.app.getInputManager();
this.viewPort = this.app.getViewPort();
}

@Override
public void setEnabled(boolean enabled) {
// Pause and unpause
super.setEnabled(enabled);
if(enabled){
// init stuff that is in use while this state is RUNNING
rootNode.attachChild(localRootNode);
guiNode.attachChild(localGuiNode);
// call custom methods…
} else {
// take away everything not needed while this state is PAUSED
rootNode.detachChild(localRootNode);
guiNode.detachChild(localGuiNode);
}
}

public void startGame(){
nifty.gotoScreen(“hud”);
startScreenState.setEnabled(false);
runningScreenState.setEnabled(true);
}

@Override
public void update(float tpf) {

}
}

[/java]

In the main file, the following same lines respond correctly to an actionListener (so the screenstates are correctly registered etc.):

[java]
nifty.gotoScreen(“hud”);
startScreenState.setEnabled(false);
runningScreenState.setEnabled(true);
[/java]

So, does anyone know why it isn’t working this time? Thanks in advance.

Please, show how your button is in your xml.

@glaucomardano: this is my button in xml (although I think this is not the problem, since the Nifty switch is processed well - the AppState part isn’t).

[xml]
<?xml version=“1.0” encoding=“UTF-8”?>
<nifty xmlns=“http://nifty-gui.sourceforge.net/nifty-1.3.xsd
xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance
xsi:schemaLocation=“http://nifty-gui.sourceforge.net/nifty-1.3.xsd http://nifty-gui.sourceforge.net/nifty-1.3.xsd”>

<useStyles filename=“nifty-default-styles.xml” />
<useControls filename=“nifty-default-controls.xml” />

<screen id=“start” controller=“mygame.StartScreenState”>
<layer id=“background” backgroundColor="#000f">
</layer>
<layer id=“foreground” backgroundColor="#0000" childLayout=“vertical”>

  &lt;panel id="panel_top" height="20%" width="100%" align="center" childLayout="vertical"
         backgroundColor="#f008"&gt; 
      &lt;text text="Title - User name: ${CALL.getPlayerName()}" font="Interface/Fonts/Default.fnt" width="100%" height="100%" wrap="true"/&gt; 
  &lt;/panel&gt;
  &lt;panel id="panel_mid" height="50%" width="100%" align="center" childLayout="vertical"
         backgroundColor="#0f08"&gt;            
  &lt;/panel&gt;
  &lt;panel id="panel_bottom" height="30%" width="100%" align="center" childLayout="horizontal"
         backgroundColor="#00f8"&gt;  
    &lt;panel id="panel_bottom_left"  height="100%" width="50%" align="center" childLayout="vertical"
         backgroundColor="#f058"&gt;
      &lt;control name="button" label="Start" id="StartButton" align="center" valign="center" 
                visibleToMouse="true" &gt; 
        &lt;interact onClick="startGame()"/&gt;
      &lt;/control&gt;
    &lt;/panel&gt; 
    &lt;panel id="panel_bottom_right" height="100%" width="50%" align="center" childLayout="vertical"
         backgroundColor="#f082"&gt;
      &lt;control name="button" label="Quit" id="QuitButton" align="center" valign="center" 
               visibleToMouse="true" &gt; 
        &lt;interact onClick="quitGame()"/&gt;
      &lt;/control&gt;  
    &lt;/panel&gt;               
  &lt;/panel&gt;
&lt;/layer&gt;

</screen>
[/xml]

I don’t see anywhere in the code you posted that is actually setting startScreenState or runningScreenState that is used in this code block:

[java]
public void startGame(){
nifty.gotoScreen(“hud”);
startScreenState.setEnabled(false);
runningScreenState.setEnabled(true);
}
[/java]

So you may be getting a NullPointerException which nifty will swallow and throw away (at least way back when I used it).

@pspeed: Unfortunately, I still don’t get it. I already set startScreenState and runningScreenState in the Main file:

[java]
public class Main extends SimpleApplication
implements ScreenController {

public boolean isRunning = false; // starts at startscreen
public StartScreenState startScreenState;
public RunningScreenState runningScreenState;
public static SimpleApplication app;
public Nifty nifty;
public Screen screen;

// Start the application
public static void main(String[] args) {
app = new Main() {};
app.start();
}

@Override
public void simpleInitApp() {

startScreenState    = new StartScreenState(this);      
runningScreenState  = new RunningScreenState(this);
 
NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay( assetManager, 
                                                    inputManager, 
                                                    audioRenderer, 
                                                    guiViewPort);

// Create a new NiftyGUI object /
nifty = niftyDisplay.getNifty();

// register nifty screencontrollers
nifty.registerScreenController(startScreenState, 
                               runningScreenState, 
                               feedbackScreenState);

// Read your XML and initialize your custom ScreenController 
nifty.fromXml("Interface/fields.xml", "start", this);

// attach the Nifty display to the gui view port as a processor
guiViewPort.addProcessor(niftyDisplay);

// application starts at start screen
nifty.gotoScreen("start");
stateManager.attach(startScreenState);
startScreenState.setEnabled(true);
 
stateManager.attach(runningScreenState);
runningScreenState.setEnabled(false);
stateManager.attach(feedbackScreenState);

// disable the fly cam
flyCam.setDragToRotate(true);

}

//Nifty GUI ScreenControl methods
public void bind(Nifty nifty, Screen screen) {
this.nifty = nifty;
this.screen = screen;

}
[/java]

Presumably Main is a different class than the one you are calling startGame() on?

Curious, have you been doing OOP development long?

@pspeed: I would say it’s not. After trying a lot, I can’t believe it’s still not working (getting a simple button to work can’t be that hard, can it?). So I’m open for more suggestions. Thanks for having a look at it anyway.
And no - a few weeks :slight_smile:

This is kind of basic OO programming skill. I highly recommend you spend some time learning the basics before going too much farther.

Basically, if you have two classes:
[java]
class Foo {
SomeClass field1;
}

class Bar {
SomeClass field1;
}
[/java]

field1 in instances of class Bar doesn’t get magically set just because you have set a field1 in an instance of class Foo. Nothing in that class will get set unless you actually set it. And in your case you aren’t.

Simple debugging: put a System.out.println() in your startGame() method that prints the values of those fields. I’ll bet they are null.

@pspeed: you’re right, those fields are null.

Although it might seem trivial, I can’t get it working - even after many tries. So please help me: how can I reinitialize or set startScreenState and runningScreenState in my startGame() method?

The next code doesn’t do the trick.
[java] startScreenState = new StartScreenState(this); [/java]

You need to pass the value in.

@pencil said: @pspeed: you're right, those fields are null.

Although it might seem trivial, I can’t get it working - even after many tries. So please help me: how can I reinitialize or set startScreenState and runningScreenState in my startGame() method?

The next code doesn’t do the trick.
[java] startScreenState = new StartScreenState(this); [/java]

Well, for one thing, inside startScreenState you no longer need to refer to startScreenState because you already are StartScreenState.
setEnabled(false);
…is fine for that.

For the other, pass runningScreenState in on the constructor along with application… or look up the state or whatever.

Metaphorically speaking, you are trying to write a book but you haven’t even learned to form your letters yet. You will stumble for days and days over these fundamentally simple things that come up all the time. I highly recommend you start with some simpler projects just to learn how to program first. Maybe a simple text adventure or something just to take all of this other stuff out of the mix.

Edit: and note, just passing it in on the constructor is not enough… you will have to then set the local field to that field. this.runningScreenState = runningScreenState (or whatever you named the parameter).

For those with the same problem, here is my solution:

  • In Main, make sure that the screenstates are public:
    [java]
    public StartScreenState startScreenState;
    public RunningScreenState runningScreenState;
    [/java]

  • To approach methods (here: setEnabled() ) or variables in other screenstates, use:
    [java]
    Main.app.getStateManager().getState(StartScreenState.class).setEnabled(false);
    Main.app.getStateManager().getState(RunningScreenState.class).setEnabled(true);
    [/java]

  • At the same time, let Nifty change the gui:
    [java]
    nifty.gotoScreen(“hud”);
    [/java]

In this way you can get the basic things - like a start button - do what you expect them to do.

And this is very weird, there’s no much sense in making those instance variables public if you don’t use them at all. Also, there is a OO design principle that says:
“Only talk to your friends!”. I hope you figure out what I’m talking about :).