Nifty GUI and Dynamic Changes

I found basically only 2 ways to have GUI elements move (and also vanish and reappear) based on “player” actions:
a) Projecting Nifty GUI on geometry as a texture,
b) Updating Nifty GUI using something.getParent().layoutElements();,

My questions are:
1. Which way is more optimal (meaning: will force garbage collector later and less frequently and will use less resources to calculate)? For the record option b I focused on first feel a little slow (I mean movement is stutter-ish and FPS drops from my default 1k+ down to 400 while moving mouse very fast, not to mention Label that I move seem to be unable to “keep up with mouse” sometimes). Never had that effect with scene graph objects mimicking mouse movement.
2. Can I project several different Nifty GUI Elements to several different geometries and also have normal overlay GUI with other stuff at the same time?
3. How do I change button (or another Element’s) text? I found something.findControl("Button_ID", ButtonControl.class).setText("qpencja"); to be working but my IDE screams loudly for this way being deprecated with every compilation and changing ButtonControl.class to Button.class (which was suggested in several topics here) just don’t work.
[EDIT: Question 3.] after changing something.findControl("Button_ID", ButtonControl.class) to something.findNiftyControl("Button_ID", Button.class) “deprecated” is no more. Sounds like some legacy junk… Strange thing though - the way presented in tutorial (using TextRenderer) don’t work at all (exception) and is even strongly disadvised in several topics here.

Last question COMPLETELY OUT OF TOPIC: How do I change language in forum text editor? It somehow changed last time I used it to my national language and now writing posts in English give me one big serpentine of red underlining… This happened only here to it must be something HUB.related.

Nifty is not performance wised api for game effects, it supouse to be used only to show popups and gui for the user.
It has internal effects to move from one menu to another but just this.
If you are trying to do some special effect in your game, I dont recomend nifty.
What exactly are you trying to do ?

I assume that was answer to point 1 of my question so:

  • For now I need to have tooltip “window” just like comic balloon dialog that will mimic my mouse movements all the time.
  • Later I will also need small tooltips that will be created after selecting “something” near this something’s location and will instantly vanish after selecting anything else.

If performance ( fps ) is important at the moment this tool-tips shows up, goes for another gui lib, like lemour or tonegui, or do like me, write some simple gui functions using mat shadders or pics.

About your second question, this is the function I use to change text :

public void nifty_changeText(String obj,String newvalue) {
    Element elementToFill = nifty.getCurrentScreen().findElementByName(obj);
    elementToFill.getRenderer(TextRenderer.class).setText( newvalue );
}

Would You be so kind and provide download links for:

  • Tonegod and Lemur download pages,
  • Tonegod and Lemur documentation pages,
    …so I can quickly evaluate if they make sense for my project?

Tool tips work fine in nifty and don’t have any performance issues. I use them all the time for my items. Internally, tool tips just use setConstraintX / setConstraintY and then call layoutElements to move the position.

In order to really make it match your mouse movements you can setup an effect similar to the tooltip and just have that effect always be active. Updating it in your game loop though introduces a delay since the position is only updated in nifty’s update loop which is where you get your stuttering from. I’ve never noticed an fps drop from doing that.

Create such tooltip following mouse in empty jMonkey project. Then start moving Your mouse like You get Parkinsons Disease… Voila, Your FPS just got cut in half. But when I do same stuff with several geometries following my mouse I don’t get any delays.

As for second part of Your post (matching mouse movements) - could You provide an example? I didn’t dig into Nifty effects much yet, but I don’t remember having tooltip effect in documentation.

If you are just creating a panel and having it “follow” your mouse then you are going to run into the problem I described. I’ve never seen it affect the fps, but I imagine it could due to the synchronization between what you set and the nifty update loop. You would have to give me the sourcode you are using for your minimal example to tell you more.

In order to use nifty you really need to look into the source code. The tooltip “effect” source code is Here. Nifty isn’t very well documented so I use the source code extensively in order to figure out how to do anything beyond the examples.

If the synchronization between 2 update loops is the reason here then I believe using the effect won’t help here. That is because mouse position is tracked inside jMonkey update loop and then inside the same update loop it is send as setConstraint to the nifty Element. Here’s my code:

public void initialize (AppStateManager stateManager, Application Main) {
    super.initialize(stateManager, Main);

    niftyJmeDisplay = new NiftyJmeDisplay(
            assetManager, inputManager, audioRenderer, guiViewPort);
    nifty = niftyJmeDisplay.getNifty();
    guiViewPort.addProcessor(niftyJmeDisplay);

    nifty.loadStyleFile("nifty-default-styles.xml");
    nifty.loadControlFile("nifty-default-controls.xml");

    // <screen>
    nifty.addScreen("Game Screen", new ScreenBuilder("Game Screen"){{
        controller(new DefaultScreenController());

        // <layer>
        layer(new LayerBuilder("Game Layer") {{
            childLayoutAbsolute();

            // <panel>
            panel(new PanelBuilder("Toolbar Panel") {{
                childLayoutAbsolute();
                width("100px");
                height("768px");
                x("924px");
                y("0px");
                backgroundColor("#666f");
            }});
            // </panel>

            // <panel>
            panel(new PanelBuilder("Tooltip Panel") {{
                childLayoutAbsolute();

                // GUI element
                control(new LabelBuilder("Tooltip", "Tooltip Text"){{
                    height("100px");
                    width("140px");
                    backgroundColor("#666f");
                    textHAlignCenter();
                    textVAlignCenter();

                }});
                // GUI element

            }});
            // </panel>

        }});
        // </layer>

    }}.build(nifty));
    // </screen>

    nifty.gotoScreen("Game Screen");
}

public void update(float tpf) {
    Vector2f mousePosition2d = main.getStateManager().getState(AppState_Cursor_Control.class).mousePosition2d;
    Vector3f mousePosition3d = main.getStateManager().getState(AppState_Cursor_Control.class).mousePosition3d;
    Element tooltip = nifty.getCurrentScreen().findElementByName("Tooltip");
    tooltip.setConstraintY(new SizeValue(768 - (Math.round(mousePosition2d.y)) + "px"));
    tooltip.setConstraintX(new SizeValue(Math.round(mousePosition2d.x) + 20 + "px"));
    tooltip.findNiftyControl("Tooltip", Label.class).setText(
        "Mouse Pixel Position:\n" +
        "X: " + Float.toString(mousePosition2d.x) + " Y: " + Float.toString(mousePosition2d.y) + "\n" +
        "Mouse Map Position: \n" +
        "X: " + new DecimalFormat("###.###").format(mousePosition3d.x) + " Y: " + new DecimalFormat("###.###").format(mousePosition3d.y) + "\n" +
        "Mouse Grid Position: \n" +
        ""
    );
    tooltip.getParent().layoutElements();
}

Yea, I’m not getting an fps drop at all. That fps is around what I get on this machine with a blank screen.

I used the following code on a blank project:

public class Main extends SimpleApplication {

    private NiftyJmeDisplay niftyDisplay;

    @Override
    public void simpleInitApp()
    {
	getFlyByCamera().setEnabled(false);
	niftyDisplay = new NiftyJmeDisplay(getAssetManager(), getInputManager(), getAudioRenderer(), getGuiViewPort());
	
        Nifty nifty = niftyDisplay.getNifty();
	    getGuiViewPort().addProcessor(niftyDisplay);
        nifty.loadStyleFile("nifty-default-styles.xml");
        nifty.loadControlFile("nifty-default-controls.xml");

        // <screen>
        nifty.addScreen("Game Screen", new ScreenBuilder("Game Screen"){{
        controller(new DefaultScreenController());

        // <layer>
        layer(new LayerBuilder("Game Layer") {{
            childLayoutAbsolute();

            // <panel>
            panel(new PanelBuilder("Toolbar Panel") {{
                childLayoutAbsolute();
                width("100px");
                height("768px");
                x("924px");
                y("0px");
                backgroundColor("#666f");
            }});
            // </panel>

            // <panel>
            panel(new PanelBuilder("Tooltip Panel") {{
                childLayoutAbsolute();

                // GUI element
                    control(new LabelBuilder("Tooltip", "Tooltip Text"){{
                        height("100px");
                        width("140px");
                        backgroundColor("#666f");
                        textHAlignCenter();
                        textVAlignCenter();

                    }});
                    // GUI element

                }});
                // </panel>

            }});
    
          }}.build(nifty));

          nifty.gotoScreen("Game Screen");
    }

      @Override
      public void simpleUpdate(float tpf) {
          Nifty nifty = niftyDisplay.getNifty();
          Vector2f mousePosition2d = new Vector2f(Mouse.getX(), Mouse.getY());
          Element tooltip = nifty.getCurrentScreen().findElementByName("Tooltip");
          if (tooltip != null) {
            tooltip.setConstraintY(new SizeValue(600 - (Math.round(mousePosition2d.y)) + "px"));
            tooltip.setConstraintX(new SizeValue(Math.round(mousePosition2d.x) + 20 + "px"));
            tooltip.findNiftyControl("Tooltip", Label.class).setText(
                "Mouse Pixel Position:\n" +
                "X: " + Float.toString(mousePosition2d.x) + " Y: " + Float.toString(mousePosition2d.y) + "\n" +
                "Mouse Map Position: \n" +
                "Mouse Grid Position: \n" +
                ""
            );
            tooltip.getParent().layoutElements();
          }
      }

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

Well for me FPS is stabilized between 1400 and 1700 when standing still and drops to 800-1200 when I Parkinson-Move mouse all around the place. Btw. nice machine You have there :wink:

As for this source code You gave me - I have absolutely no idea how to pull the “panel movement match the mouse movement perfectly” trick out of this :frowning:

[EDIT] A little side question. Color encoding still doesn’t work in stable jMe3 right? Because simply throwing #000000# into string gets unrecognized and thrown as error.

Note: Fps drops at such high numbers don’t matter at all as no monitor in the world will be able to display 800 fps. An average monitor runs at 60Hz, some gaming monitors run at 144Hz so if your fps are higher than that there is no problem at all. You would havae a problem though when the fps dropped from 60 to 30 for example depending on the fps rate you are aiming for.

Of course the FPS meter in JME is not an actual FPS but potential FPS (and of course such high numbers are there only because there is nothing on scene graph). It shows how many updates per second JME is calculating which doesn’t change the fact that actual presentation on screen is done with default monitor refresh rate which in 2015 is 60 FPS in 99% of cases :smile:

But based on this FPS meter I can more or less decide how much more stuff I can throw in there and still have everything working smoothly :smile:

Yeah but you should only start worrying about the nifty performance once you know that it is really slowing your game down so that you have to change it. But of course it is right that you can see how the fps change but I think it is more important how they will behave once you exceed the performance limits and it is not important to worry about it in such an early state i guess

Two more questions that kinda came out of nowhere when I least expected them:
a) How to dynamically change (or just access) nifty element variables such as background or font? I can’t find any “set” method for those. Are they only staticaly declared while defining element (either in java or xml)?
b) Why in some cases setConstraintHeight works and in others setHeight work (while the other one doesn’t)? I have setHeight for my Panel and setConstraintHeight for my Label but those 2 doesn’t work the other way around. Just like if I left those places with empty value.

A - I’ve never tried changing font dynamically but its an option for the text renderer IE…

nifty.getScreen("yourScreen").findElementByName("myElement").getRenderer(TextRenderer.class)

There is also a change font effect you can use.

B - They are both used for different things. The naming is a little confusing and I have no idea why. I imagine its something they will clear up with 2.0 with all the API cleanup they are doing.

To be honest, having to use “effects” and their complicated syntax in Nifty to achieve anything static feel a little heretic to me. Especially when I see such basic stuff as border around GUI element in “effects” list in documentation. My previous experience was with JavaFX though which is nearly perfect in terms of being a GUI framework. But anyway could You show me example for static “effect” syntax? Couldn’t find those anyway… All I found was “onHover, onThis, onThat”…

As for:
A. Several people here said that using such low-level stuff as Text Renderer is very bad habit. They insisted on using findNiftyControl(“somename”, Label.class).setText to get to the text instead. And this doesn’t let me change the font.
A(primo). What about changing background?
B. Could You tell me what are those methods intended usages? How are they different?

A: Well you could use the TextRenderer to set the font and use the control (Label.class) to set the text. That’s what I do. About the background, you can use the ImageRenderer to change the background.
B: I would advise you to use the label control to set the text. You also getting no information about the current text via TextRenderer. But in general no big difference, I would say.

B. Label Control is exactly what I’m doing now. But I’d like to use similar “control” way to change background and font instead of dealing with buffers.

I don’t think there is a way to set the background/font via control but I am not 100% sure.