Need Help with Nifty-GUI

Ok, So I am trying to get the screen controller to work and I am following this tutorial: https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:nifty_gui_scenarios

Am I doing this correctly?

Main.java
[java]public class Main extends SimpleApplication {

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

@Override
public void simpleInitApp() {
    NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
    Nifty nifty = niftyDisplay.getNifty();
    nifty.fromXml("Interface/start.xml", "start");
    guiViewPort.addProcessor(niftyDisplay);
    flyCam.setDragToRotate(true);
}

@Override
public void simpleUpdate(float tpf) {
    //TODO: add update code
}

@Override
public void simpleRender(RenderManager rm) {
    //TODO: add render code
}

}[/java]

SplashScreen.java (Controller class, I think):
[java]public class SplashScreen implements ScreenController {

public void bind(Nifty nifty, Screen screen) {
}

public void onStartScreen() {

}

public void onEndScreen() {
}  

}[/java]

start.xml:
[java]<?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”>
<screen id=“start” controller=“mygame.SplashScreen”>
<layer id=“layer” backgroundColor="#000f" childLayout=“center”>
<panel id=“panel1” align=“center” valign=“center” backgroundImage=“Interface/Logo 1080p Black.png”>
<effect>
<onStartScreen name=“fade” startDelay=“8000” start="#f" end="#0" length=“3000” neverStopRendering=“true”/>
</effect>
</panel>

        &lt;panel id="panel2" align="center" backgroundColor="#000f" &gt;
            &lt;effect&gt;
                &lt;onStartScreen name="fade" startDelay="3000" start="#f" end="#0" length="3000" neverStopRendering="true"/&gt;
            &lt;/effect&gt;
        &lt;/panel&gt;
    &lt;/layer&gt;
&lt;/screen&gt;

</nifty>[/java]

Ok my question is:

If I have done everything correctly, what is the job of the controller class? What are those methods for (bind, onStartScreen, onEndScreen)? What can I do with those methods?

EDIT: It works the way its supposed to but I don’t get the part about the Screen Controller.

Screen controller is acting like a “listener” for nifty-gui events . In there you can add methods to react from mouse click or keyboard input . The tree methods you mention are called by nifty-gui at a particular time . When it creates your ScreenController instance it calls bind so you can retrieve a valid Nifty instance or you can set up some other dynamic elements . onStartScreen and onEndScreen are called once you enter in a screen and after you left it. For example if you are in “start” screen and you call somewhere nifty.goto(“main”) , nifty will call onEndScreen in your “start” screenController and then onStartScreen in you “main” screenController .
I hope this helps :slight_smile: you can also check the nifty-gui manual here .

Thanks that helps a lot. I have one more question. I read that you can give the controller class AbstractAppState to access the update and initialize methods in the Nifty Tutorials (https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:nifty_gui_scenarios). Is that a viable option? Thanks

Yes. As far as I know best practice is for Nifty screen controllers in JME to be appstates. As in:
[java]
public class LoginScreenController
extends AbstractAppState
implements ScreenController {
}
[/java]

Thanks. I have one more question. Does the initialize and update run from the controller + abstract app state run automatically when the XML file is called? Or do I have to add some more lines of code for the update and initialize to work. I am not sure if that makes sense but I can explain further if it does not make sense.

1 Like

The way app states work is that you have to attach them in order for the application to even know they’re there. Typically I do this in simpleInitApp() [or some method invoked by simpleInitApp()] like so:
[java]
MapViewState mapViewState = new MapViewState();
stateManager.attachAll(mainViewState);
[/java]

Once you attach the app state, the state manager takes care of invoking its initialize() method during its next update. The manager also takes care of invoking the app state’s update() method on each update, provided the app state is enabled.

Loading the XML won’t by itself attach any app states. I usually set it up the other way around, so that the app state’s initialize() method registers the app state as a screen controller and loads the XML, like so:
[java]
public void initialize(AppStateManager stateManager,
Application application) {
super.initialize(stateManager, application);

    nifty.registerScreenController(this);
    nifty.addXml("Interface/foo.xml");
}

[/java]

I have a couple questions:

  1. Where do you put this:
    [java]NiftyJmeDisplay niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
    Nifty nifty = niftyDisplay.getNifty();
    guiViewPort.addProcessor(niftyDisplay);[/java]
    Do you put it in the simpleInitApp or do you put it in the initialize method of the state.

  2. In your code:
    [java]public void initialize(AppStateManager stateManager,
    Application application) {
    super.initialize(stateManager, application);

     nifty.registerScreenController(this);
     nifty.addXml(“Interface/foo.xml”);
    

    }[/java]
    Where do you initialize “nifty”?

I am also getting an error: "No loader for registered type ’ ’ ". This stuff is confusing me. Is there any sample code I can take a look at to see exactly what I am doing wrong?

Thanks for your help. I really appreciate it.

I generally instantiate the NiftyJmeDisplay in simpleInitApp() and provide a getNifty() accessor in my application, which I then invoke in each app state’s initialize() method. I generally invoke addProcessor() or removeProcessor() in the app state’s setEnabled() method.

But there are many other ways one could do it.

Examples in the JmeTests project which use Nifty include: TestCinematic, TestAppStates, TestNiftyExamples, TestNiftyGui, and TestNiftyToMesh.

Thanks a lot for help. There is now way I would have understood it without your help. I just have one more question. I have a splash screen with a fade effect. After the fade effect has ended, I want to start a new screen. I know how to move to another state but I can’t figure out how to detect if the last fade effect has ended. Thanks for your help.

1 Like

You could use the onStartScreen method since it’s called after all star screen effects , but I’d rather use this : add a callback to the last fade effect . Using xml is quite simple just put an attribute on effect element : [java]
<effect>
<onStartScreen name=”fade” startDelay=”8000″ start=”#f” end=”#0″ length=”3000″ neverStopRendering=”true”
onEndEffect=“yourMethodHere()” />
</effect>

[/java]
yourMethodHere() must be in your screen controller :slight_smile: you can find further information in the manual :slight_smile:

I hope this helps!

Ahh… I was doing the same thing except I was putting it in a control tag for some reason. Thanks for the help!

I am having some trouble with positioning elements.

This image shows a 1080p screen. I want my buttons to be in the center of the red box. As you can see the red box is not exactly half of the screen. So to position this, would I need to use absolute layout? If I use absolute layout, what happens when the resolution changes? Do the buttons move proportionally?

Also when I tried the absolute layout with a button, the hit box stayed in the center. Do I have to also position the layer? This is my XML file for the button.

[java]<layer id=“layer” backgroundColor="#000f" childLayout=“center”>

        &lt;!-- A panel with a background image --&gt;
        &lt;panel id="panel1" align="center" valign="center" backgroundImage="Interface/Images/Menu/MainMenu.png"&gt;

        &lt;/panel&gt;
        
        &lt;!-- A panel with the exit button --&gt;
        &lt;panel id="panel" height="5%" width="5%" align="center" valign="center" childLayout="center" visibleToMouse="true"&gt;
            &lt;interact onClick="quit()"/&gt;
            &lt;effect&gt;
                &lt;onHover name="textColor" color="#ff7200"/&gt;
            &lt;/effect&gt;
            &lt;text id="text" font="Interface/Fonts/Champagne.fnt" color="#FFFFFF" text="QUIT" align="center" valign="center" /&gt;
       &lt;/panel&gt;

        &lt;!-- A panel that goes from black to transparent to reveal the image above to create a fade in effect --&gt;
        &lt;panel id="panel2" align="center" backgroundColor="#000f" &gt;
            &lt;effect&gt;
                &lt;onStartScreen name="fade" startDelay="3000" start="#f" end="#0" length="3000" neverStopRendering="true"/&gt;
            &lt;/effect&gt;
        &lt;/panel&gt;

</layer>[/java]

I can correct anything if that didn’t make sense. Thanks for the help!

UPDATE: Ok, So I figured out how to put in the center. All I had to do was make a panel with the width and aligned to the right, and have a child layout of center. But my next question would be how would I move it downwards?

@akshaypathak1011 said: But my next question would be how would I move it downwards?

There’s more than one way. If you know the exact coordinates you want, you could use a panel with childLayout=“absolute”.

About your update , I have overall advice since the image it’s quite clear but I don’t get where you are stuck . I used to use several panels to achieve my desired layout maybe in your case also the margin attribute would give you some helps. For instance now that you have a panel in the right with center layout , you could add two more panel one with valing top and an other with vertical childlayout for buttons , and each button with a lttle margin on top . This just my suggestions , I didn’t test them tough.