NiftyGui Tutorial not working

Hi,

first of all let me say thank you for your hard work on this game engine, as a Java developer I really enjoy working with it. The engine itself is also working very good apart from some performance problems which are probably my fault.

But the thing which almost made me quit using this engine is NiftyGUI. I have tried to get it to work for several days now but I have no clue what I’m doing wrong so I created this account in hope to get some help here.

I read the Nifty tutorial and tried to reproduce it but it doesn’t work. So first of all here is the code I ended up with:

Structure:
assets\Interface\screen.xml
assets\Interface\face1.png
assets\Interface\hud-frame.png
assets\Interface\start-background.png
src\mygame\Main.java
src\mygame\MyStartScreen.java

Main.java

package mygame;

import com.jme3.app.SimpleApplication;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.RenderManager;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import de.lessvoid.nifty.Nifty;

public class Main extends SimpleApplication {

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

    @Override
    public void simpleInitApp() {
        Box b = new Box(1, 1, 1);
        Geometry geom = new Geometry("Box", b);

        Material mat = new Material(assetManager, "Common/MatDefs/Misc/Unshaded.j3md");
        mat.setColor("Color", ColorRGBA.Blue);
        geom.setMaterial(mat);

        rootNode.attachChild(geom);

        NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
        Nifty nifty = niftyDisplay.getNifty();
        nifty.fromXml("Interface/screen.xml", "start", new MyStartScreen());
        guiViewPort.addProcessor(niftyDisplay);
        flyCam.setDragToRotate(true);
    }

    @Override
    public void simpleUpdate(float tpf) {
    }

    @Override
    public void simpleRender(RenderManager rm) {
    }
}

MyStartScreen.java

package mygame;

import com.jme3.app.Application;
import com.jme3.app.state.AbstractAppState;
import com.jme3.app.state.AppStateManager;
import de.lessvoid.nifty.Nifty;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;

public class MyStartScreen extends AbstractAppState implements ScreenController {

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        super.initialize(stateManager, app);
    }

    @Override
    public void update(float tpf) {
    }

    @Override
    public void cleanup() {
        super.cleanup();
    }

    public void bind(Nifty nifty, Screen screen) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void onStartScreen() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void onEndScreen() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void startGame(String nextScreen) {
        nifty.gotoScreen(nextScreen);
    }

    public void quitGame() {
        app.stop();
    }
}

screen.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.MyStartScreen">
        <layer id="background" childLayout="center">
            <image filename="Interface/start-background.png"></image>
        </layer>
        <layer id="foreground" childLayout="vertical">
            <panel id="panel_top" height="25%" width="75%" align="center" childLayout="center">
                <text text="My Cool Game" font="Interface/Fonts/Default.fnt" width="100%" height="100%" />
            </panel>
            <panel id="panel_mid" height="50%" width="75%" align="center" childLayout="center">
                <text text="Here goes some text describing the game and the rules and stuff. Incidentally, the text is quite long and needs to wrap at the end of lines. ..." font="Interface/Fonts/Default.fnt" width="100%" height="100%" wrap="true" />
            </panel>
            <panel id="panel_bottom" height="25%" width="75%" align="center" childLayout="horizontal" >
                <panel id="panel_bottom_left" height="50%" width="50%" valign="center" childLayout="center">  
                    <control name="button" label="Start" id="StartButton" align="center" valign="center" visibleToMouse="true" > 
                        <interact onClick="startGame(hud)"/>
                    </control>
                </panel>
                <panel id="panel_bottom_right" height="50%" width="50%" valign="center" childLayout="center">
                    <control name="button" label="Quit" id="QuitButton" align="center" valign="center"></control>
                </panel>
            </panel>
        </layer>
    </screen>
    <screen id="hud" controller="mygame.MyStartScreen">
        <layer id="background" childLayout="center">
            <image filename="Interface/hud-frame.png"></image>
        </layer>
        <layer id="foreground" childLayout="horizontal">
            <panel id="panel_left" width="80%" height="100%" childLayout="vertical" ></panel>
            <panel id="panel_right" width="20%" height="100%" childLayout="vertical">
                <panel id="panel_top_right1" width="100%" height="15%" childLayout="center">
                    <control name="label" color="#000" text="123" width="100%" height="100%" />
                </panel>
                <panel id="panel_top_right2" width="100%" height="15%" childLayout="center">
                    <image filename="Interface/face1.png" valign="center" align="center" height="50%" width="30%" ></image>
                </panel>
                <panel id="panel_bottom_right" height="50%" width="50%" valign="center" childLayout="center">  
                    <control name="button" label="Quit" id="QuitButton" align="center" valign="center" visibleToMouse="true" > 
                        <interact onClick="quitGame()"/>
                    </control>
                </panel>
            </panel>
        </layer>
    </screen>
</nifty>

First problem: Despite extending from AbstractAppState, MyStartScreen can’t find the app- and nifty-objects in the startGame(String) and quitGame() methods. I was able to solve this by adding a constructor to set them, but I don’t know if that’s the correct way to do it.

Second problem: If I’m running the program it’s throwing the UnsupportedOperationException in the bind(Nifty, Screen) method. Of course you can solve this by simply removing that code, but why is it even there in the first place?

Third problem: If I run this sample with my own constructor and after removing the UnsupportedException code I can see my GUI, but the interaction does not work. If I click on the buttons nothing happens and by debugging I noticed that my custom methods in MyStartScreen don’t even get called.

It’s really discouraging if the first tutorial of Nifty doesn’t work and I hope you can help me solve these problems.

Best regards
Gator

Mmm, I think you need to attach the appstate. Now it is just an object floating in the space.

MyStartScreen startScreen = new MyStartScreen();
stateManager.attach(startScreen);
nifty.fromXml(“Interface/screen.xml”, “start”, startScreen);

These is no single correct way to use the app states. But I’m pretty sure you need to attach them if you want to use/activate them. And the bind etc. you should assign the variables to local fields instead of throwing exception. Nifty calls this for your convenience so you get the reference.

See: http://wiki.jmonkeyengine.org/doku.php/jme3:advanced:application_states

But I suspect that if you just attach the app state you create, all your problems are solved.

Thanks for the reply!

I tried your solution but unfortunately that doesn’t seem to change anything. “nifty” and “app” are still unknown in “MyStartScreen” and the interaction still doesn’t work.

Assign the variables to local fields? Can you go a bit deeper in that, because I don’t really know what to do in these methods, what kind of local fields could be used here?

Like in the link you provided I’m now setting the Application in the initialize-method.

private SimpleApplication app;

    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        super.initialize(stateManager, app);
        this.app = (SimpleApplication) app;
    }

This solves one problem, though I still don’t know the best way to get the Nifty-object.

Similarly on:

public void bind(Nifty nifty, Screen screen) {
// throw new UnsupportedOperationException(“Not supported yet.”);
this.nifty = nifty;
this.screen = screen;
}

Then you can interact with Nifty from your app state since you got the reference.

That was the last bit I was missing, now everything works as intended.
I’ll keep this code as a reference so I don’t run into the same problem again, thanks a lot for the help tonihele :smile:

No problem. Nifty & AppStates, they both are powerful but require some degree of tears to manage when starting out.

The original tutorial code in Google code link uses the Main directly and doesn’t even try to use app states. But the code on the page sure does and this kind of usage isn’t so clear perhaps.