Full screen and centered menu. Lemur

Hi, i’m quite an idiot and find myself lost trying to understand Lemur documentation. I’m trying to make a main menu to my game and felt really dumb while reading the docs. Anyway, managed to make this code to center my main menu but it doesn’t work.

public class MainMenuScreen extends AbstractAppState{
    Node guiNode = new Node("guinode");
    
    SimpleApplication app;
    int ratio;
   
    @Override
    public void initialize(AppStateManager stateManager, Application app) {
        
         super.initialize(stateManager, app);
       ((SimpleApplication) app).getRootNode().attachChild(guiNode);
       GuiGlobals.initialize(app);
       Container myWindow = new Container(new BorderLayout());
       Panel backgroundImg = new Panel();

        Vector3f size= new Vector3f(percentageSize(100, app.getCamera().getWidth()), percentageSize(100, app.getCamera().getHeight()), 0);
        backgroundImg.setPreferredSize(size);
        
        myWindow.addChild(backgroundImg);

        Vector3f position = new Vector3f(centered(app.getCamera().getWidth()), centered(app.getCamera().getHeight()), 0);
        backgroundImg.setLocalTranslation(position);

        QuadBackgroundComponent bComponent = new QuadBackgroundComponent( app.getAssetManager().loadTexture("Textures/tiles.png"));
        backgroundImg.setBackground(bComponent);  
   
         
        guiNode.attachChild(myWindow);
    
      
       
      
       
    }
    /** Sets the size in relation to the screen 
     * 
     * 
     * @param porc percentage of the screen that's gonna fill
     * @param align WIDTH or HEIGHT to fill horizontal or vertical respectively.
     * @return
     */
    public float percentageSize(int porc,float align){
        ratio = porc;
       return (porc*align/100);
    }
    
    /**
     * Centers anything based on camera resolution
     * 
     * @return position on screen
     * call percentagesize() first to initialize ratio
     * @param align WIDTH or HEIGHT to center horizontal or vertical respectively.
     */
    public float centered(float align){
    
        return (align/2-(percentageSize(ratio,align))/2);
    }
}

This is the result, a little help?

1 Like

Well, it is placing it in the center of the screen… it’s placing the panel location (upper left corner) in the center. Probably you wanted to offset it by half the panel.

Or you can just call the utility method already setup to do this:

GuiGlobals.getInstance().getPopupState().centerInGui(myWindow);

Edit: note that for learning Lemur it can also be useful to look at the existing demos:

…and there are several open source applications that also use Lemur if you want to see how it’s used “for real”.

Edit 2: here is a semi-advanced example of a main menu app state:

…it does not center itself so the above utility call is still useful.

Some advice: extend BaseAppState instead of AbstractAppState.

BaseAppState provides some nice lifecycle methods like onEnabled()/onDisabled() and easy access to other states.

AbstractAppState is for devs who are like “f*ck you I want to do everything myself”… which is fine. But BaseAppState will ultimately save you lots of time and make your states more reusable.

i see, thanks for the advide.

Let us know how the other answer (centerInGui) works out or if there are still issues.

I never knew about that functionality…
Not sure how I made it but I am sure I have used and needed that as well.

Lurking forum gives new insights (again)

how about such way:
//---------------------------
private Picture start;
private Node menuButtons
//---------------------------
start = new Picture(“start”);
start.setImage(assman, “Interface/goPressed.png”, false);
start.setWidth(setts.getWidth()/5);
wids=setts.getWidth()/5;
heis=setts.getHeight()/7;
start.setHeight(setts.getHeight()/7);
start.setPosition(setts.getWidth()/2-wids/2, setts.getHeight()/2+heis/2);
menuButtons.attachChild(start);
//---------------------------

So much code already and it doesn’t even do clicking or keyboard/joystick navigation or focus highlighting.

…and with Lemur you can do your example in like 3-4 lines of code. And it would already have clicking, keyboard/joystick navigation, animation, focus highlighting, etc…

hey @Consti !

welcome to the forums :melting_face:

show us the menu if you get something up and working I’d be interested to see it

Hi!! related to the menu, i tried different approaches, first
GuiGlobals.getInstance().getPopupState().centerInGui(myWindow); didn’t work for me, maybe I’m to dumb to understand how to use it and instead of centering, showed the lower left corner in the center, got a little frustrated and decided to run some maths:

I want my menu to be resizable with the camera’s resolution so I worked with percentage, let’s say that my container’s width and height has to be 16% the camera’s width and height(16 as arbitrary number)

for a 16%x16% container size, setLocalTranslation(8%,10%,10% of camera’s width) (of camera’s resolution, in z used camera.width to get depth)
and it was really close to center, after some trial and error i got (-109.5f, 61.1f ,-137f)

-109.5 is 8.02% camera’s width
61.1 , is 7,96% camera’s height
-137, is 10.05% camera’s width

Then for a 22%x22% container size i got , in percentage of camera’s resolution, (11.02%,10.96%,14.1%). The augment in translation is 3%x3%x4.05% in a 6% augmented size

For each 1% you increment the container’s size, you have to push it further away from the camera 0.5% in x and y, and 0.675% in z (percentage based on camera’s resolution)

For example, you set your container’s size in-world to be 10% of camera’s resolution, and then you setLocalTranslation to (5.02% of camera.width, 4.96 of camera.height, 6% of camera.width) to get it centered, if your camera resolution is1366x768, your container’s size will be (136.6, 76.8) and it will be in (-68.5732, 38.0928, -81.96) (x negative because lemur components grow in positive x, and z negative because the camera, by default, points at (0,0,-10))

Tested on 1366x768, 1600x900 and 1906x1043

It may be sound like overthinking but it got me what i was looking for:

and the code:

 public class MainMenuScreen extends BaseAppState implements ActionListener{
    Node guiNode = new Node("guinode");
    SimpleApplication app;
    float ratio;
    private MouseInput mouseInput;
       
    @Override
    public void initialize( Application app) {
        ((SimpleApplication) app).getRootNode().attachChild(guiNode);
        Container myWindow = new Container();
        Vector3f size= new Vector3f(percentageSize(10, app.getCamera().getWidth()), percentageSize(10, app.getCamera().getHeight()), 0);
        myWindow.setPreferredSize(size);
        myWindow.setLocalTranslation(-percentageSize(5.02f, app.getCamera().getWidth()), percentageSize(4.96f, app.getCamera().getHeight()), -percentageSize(6f, app.getCamera().getWidth()));
        QuadBackgroundComponent bComponent = new QuadBackgroundComponent( app.getAssetManager().loadTexture("Textures/wallpaperdnd.png"));
        myWindow.setBackground(bComponent);
        guiNode.attachChild(myWindow);
 

       
    }
    /** Sets the size in relation to the screen 
     * 
     * 
     * @param f percentage of the screen that's gonna fill
     * @param align WIDTH or HEIGHT to fill horizontal or vertical respectively.
     * @return
     */
    public float percentageSize(float f,float align){
        ratio = f;
        return (f*align/100);
    }```
1 Like

Note: z only matters for ordering in the guiNode because it’s using an ortho camera.

This is the code I use to make a window 90% the size of the screen: (Where ‘window’ is just a Lemur Container)

        GuiGlobals globals = GuiGlobals.getInstance();
        Vector2f guiSize = globals.getPopupState().getGuiSize();
        Vector3f pref = window.getPreferredSize();
        window.setPreferredSize(new Vector3f(guiSize.x * 0.9f, guiSize.y * 0.9f, 10)); 
        globals.getPopupState().centerInGui(window);

centerInGui() should work. It even works if the panel has been scaled up and stuff. I use it all the time.

So there must have been something else moving your window after calling it.

Oh, wait…

You are adding your own guiNode to the 3D scene.

Is there a reason that you do that instead of using the standard ortho gui Node?

…that’s where the issue comes from.

yes, wanted to do 3d transitions between the different menus, like videos/clips transition, but maybe i am biting off more than I can chew

Can you be more specific? Maybe the effects can still be achieved in ortho.

Either way, Lemur will work fine in 3D, too, but as you’ve discovered the 2D GUI convenience stuff won’t work so well in that environment. Just too many variables to consider in that case.

In Mythruna, I’m actually using a hybrid GUI… it acts like 2D (same as screen size, etc.) but is really 3D… and I’ve given it to Lemur’s popup state as the main GUI node so it still works with all of the utilities. But in that case, I was very careful to set it up so that 0,0 was still the lower left corner, width,height the upper right and so on. When I’ve worked out all of the odd edge cases, I will probably include it in Lemur.

Something like this, but in-game

Ah, I see.

Another approach for that is to build your UI in 2D and the put them in an off screen buffer projected onto the sides of a cube. (It’s how I’d do that effect.) It would still have the “have to center in GUI yourself” problem, though, since it wouldn’t be a normal camera.

You might consider getting your UI working in regular 2D guiNode first and when the game is farther along adding fancy transitions. But I also know it’s fun to spend lots of time hand-crafting a game’s first look. (I have dozens of those over the last 30 years but very few finished games… so I understand the pull.)