Nifty HUD causing fps drop

Hey guys!

After passing from 3.0 to 3.1 I noticed that my game would get slower and slower as time went by. After a whille of searching I noticed it was my active HUD that was causing the problem.

What I do for my hud is rebuild my screen every frame so that I can have health bars on npcs and stuff.

In 3.0 this worked flawlessly but on 3.1 it caused the frametime to go up considerably. Starts off at 320 fps and end up at 3 fps after about 2 min.

This is how I refresh my HUD screen:

public void Refresh(){        
    String s = getActiveScreen();
    if(s.equals("")) return;              
    ScreenFactory.buildScreen(s, nifty);
    nifty.gotoScreen(s);
}

public String getActiveScreen(){
    if(nifty == null) return "";        
    Screen screen = nifty.getCurrentScreen();
    if(screen == null) return ""; 
    String ID = screen.getScreenId();        
    return ID;
}

If this is not the most elegant way to do this, please direct me to an example of an active HUD (hud that will change 60 times per second) that works?

Edit: I also noticed that when the fps is down to 3, switching to another non-active screen by doing a

nifty.removeScreen(getActiveScreen());

makes the fps go all the way back up. If I then go back to my active HUD it resumes at 3 fps.

It’s like if switching to a new screen does not free resources of the previous screen like it used to.

Nifty has been upgraded a few times since 3.0 it’s possible that the newer version doesn’t really like being abused in this way or has some subtle issue.

…this seems like a really inefficient way to work around a different issue. Health bars seem like something really easy to do outside of nifty. What do they look like?

Ok, I do refresh 60x per second (I really don’t think that should be considered as abuse…) but what if I refreshed 60x a minute to show the time? Do you think I would start getting low fps after an hour? Please, what can I do to help you find the problem? Or: How can I make nifty elements move without rebuilding the whole screen?

1: Bunch of usefull info for debugging

2: Healthbar made from nifty progress bar example, follows the npcs, appears when npc is mousepicked

Well refreshing the information is one thing, but rebuilding everything from scratch for your use case is probably a waste of resources. You can move nifty elements or change them by hand by just accessing the elements directly and making the changes you need. There are a lot of details on how to handle this on the wiki as well as the nifty bible pdf that I believe is linked in the wiki.

1 Like

As @glh3586 says in more detail:

Refreshing once per frame, not abuse.

Re-building once per frame, abuse.

Any user interface would likely build up lots of temporary garbage this way that then needs to be GC’ed. It could be even worse than that for some libraries.

By the way, if you are ever curious, I could show you how you’d do a similar UI in Lemur including a nice property panel that auto-builds itself.

Please do, I have never worked with Lemur before but it sounds nifty :slight_smile:

1 Like

Thanks, will try that

Nifty in jME 3.1 uses a batched renderer. This allows a big performance boost in complex UIs with many elements, but it does require the developer to manually dispose any screens which are inactive, so that the unused textures can be removed from the atlas.

Cool, so what is the proper way of manually disposing a screen please?

P.S. Got any examples of 2D minimap that rotates with player direction?

I guess the removeScreen method is supposed to do that.

First step would be to go through the Getting Started page to get Lemur installed + setup and stuff:

Then for the health bar, you could do it as a custom control that you attach to your mobs as needed. This control would create a ProgressBar and attach it to the guiNode. On update it would position the ProgressBar on the 2D screen based on the 3D position of the spatial to which it is attached. (Presumably you already do something like this.)

Making the ProgressBar is easy enough:
ProgressBar progress = new ProgressBar();
guNode.attachChild(progress);
progress.setLocalTranslation(appropriateLocation);

That will create a progress bar that goes from 0 to 100. If you want a different range (say 0 to maxHP) then you can do something like:
ProgressBar progress = new ProgressBar(new DefaultRangedValueModel(0, maxHP, hp));

…then to set the current HP:
progress.setValue(hp);

For a property panel, you will have to also grab the LemurProps jar from:

…include it in your project as you did the others.

There is no full documentation on PropertyPanel but there is some javadoc here which is better than nothing:
http://jmonkeyengine-contributions.github.io/Lemur/javadoc/LemurProps/com/simsilica/lemur/props/PropertyPanel.html

Basically, assuming that you have some Java object with set/get methods for your different properties (say HP, MaxHP, yaw, pitch, whatever) then you could create a panel like:

PropertyPanel properties = new PropertyPanel(“glass”); (seems there is no style-less constructor yet… my bad)

properties.addFloatProperty(“HP”, yourObject, “HP”, 0, 100, 1);
…and so on. There are both addXXField and addXXProperty methods depending on need for your particular object.

It occurs to me that this may not fit your full use-case for ‘real’ as there is currently no way to set read-only properties and there is no generic text version either. These wouldn’t be hard to add and for debug views I think it’s still probably useful.

Firefox is about to die on me as it hasn’t been restarted in 6 hours or so… or I’d say more. Anyway, maybe it’s enough to pique your curiosity. If you look around at some of my other things like IsoSurfaceDemo then you can see screen shots of the PropertyPanel using the ‘glass’ style. Styles can be changed easily enough.

Finally got it working, I love it!

Thank you very much

Whee… glad it worked. :slight_smile:

Erm…

How do I add a picture to a container?

Where can I find this information?

Like, in what way?

You mean specifically or generally? There is the docs on the wiki that I’ve been working on: Home · jMonkeyEngine-Contributions/Lemur Wiki · GitHub

…but I don’t know if they specifically answer your question. A label with an IconComponent as its icon layer is the easiest way to add an image to a container but it depends on what you mean by “add an image to a container”. Like, as a background for the container or just as an element in the container?

Both will be needed but I am primarily focused on doing something like this:

You can see under the healthbar there are the 4 corners of a square, that is an image with alpha layer. Right under it there is a blue crosshair.

So I need an invisible container that can hold an image.

Yeah, that’s no problem at all. Use a TbtBackgroundComponent and set it as the background of the container. That way your texture will even stretch intelligently.

There is a section in the docs about it:

1 Like

Hello pspeed!

Stating to get the hang of Lemur. I must say, I already like it much more then Nifty!

I working on an editor for my game to handle adding solar systems to a galaxy, then adding planets to a solar system, and then changing planet properties and stuff

When adding a child to a container it is by default added underneath. I need things in a grid kind of like:

P.S. how can I make containers draggable?

Thanks.

By default most containers have SpringGridLayout as their layout. This is a grid but by default new components create a new ‘row’ along the major axis. However, because you can pass generic constraints along then you can control this by passing rows and columns.

For the sake of this discussion, when I say ‘row’ I mean a new ‘line’ in the major axis and when I say ‘column’ I mean a new line in the minor axis. This is important because you can setup a SpringGridLayout to be flipped so that X is major and Y is minor… in which case ‘row’ and ‘column’ are flipped… but for now let’s line them up, so to speak.

So, the purely manual way:
container.addChild(myChild, row, column);

…where row and column are ints or Integers.

That allows you to be 100% explicit but it’s a pain to create a UI that way. So, if you give it only one number then it assumes it is the column in whatever row was just created… and if you give it neither it creates a new row… as you’ve seen.

So this allows you to do stuff like:

container.addChild(new Label("Name:")); // creates a new row with a label in column 0
container.addChild(new Label(theValueOfName), 1); // adds the value to the row just created but at column 1
container.addChild(new Button("Edit"), 2); // adds the button to the row just created but at column 2

For creating UIs that’s nicer because if you decide to reorder your rows then you have less search/replacing to do on row values. But you could still do it the manual way:

container.addChild(new Label("Name:"), 0, 0);
container.addChild(new Label(theValueOfName), 0, 1); 
container.addChild(new Button("Edit"), 0, 2); 

Also note: rows and columns do not need to be contiguous and you can leave cells empty also. The layout will figure it out.

Generally, the easiest way is to just add the DragHandler as a listener. Something like:
MouseEventControl.addListenersToSpatial(myContainer, new DragHandler());

The syntax of my code samples may be a little off here and there as I’m going from memory on my non-jme computer because I’m out of town at the moment.

1 Like

Hello pspeed!

I am trying to make a slider appear, can’t seem to figure out what I am doing wrong the slider simply wont appear:

    DefaultRangedValueModel m = new DefaultRangedValueModel();//50000, 1000000, 60000);       
    Slider s = new Slider(m, Axis.X, "glass") ;       
    window.attachChild(s);
    window.addChild(new Label(String.valueOf(m.getValue())));