Making gui scalable

Hi folks =),

i’m doing all the gui stuff in my game and just hit the problem on using the game with different screen resolutions. So what i do to achieve this:
for example with a panel
[java]
float panelWidth = screen.getWidth() * 0.25f;
float panelHeight = screen.getHeight() * 0.25f;
[/java]
but using sprites on a panel is causing them to be scaled really ugly. For example having a sprite 90x90pixel will be repeated/clamped to a ugly blobby thing.

I found out that using
[java]panel.setLocalScale(screenWidth/1920f);[/java] is solving the blob problem but makes the panel and all elements not interactable to the mouse, because the scale seems to be not checked in mouse event.

My question is: What are your attempts to achieve a scalable gui?

Well I dont scale my guis,

I have certain fixed element that are aligned to corners,

eg my health bar is always on the upper left, and 150px long, so higher resolution means more free space to see the world.

Then I have extensible objects,
eg the chatbox on a small screen is 4 lines
on a large one it is 10 lines and the lines can be longer before a break occurs.

Also changing the font size is a viable option.

I tried first with scaling the guis depending on the screen solution, but never found got good looking results. Especially due to differnt screen aspect ratios. A gui that looked good on a 16/9 might look buggy on a 19/10 and totaly ugly on a 4/3

Then I don’t use tonegods ui, but these methods are pretty much possible with any gui library out there.

@b00n said: Hi folks =),

i’m doing all the gui stuff in my game and just hit the problem on using the game with different screen resolutions. So what i do to achieve this:
for example with a panel
[java]
float panelWidth = screen.getWidth() * 0.25f;
float panelHeight = screen.getHeight() * 0.25f;
[/java]
but using sprites on a panel is causing them to be scaled really ugly. For example having a sprite 90x90pixel will be repeated/clamped to a ugly blobby thing.

I found out that using
[java]panel.setLocalScale(screenWidth/1920f);[/java] is solving the blob problem but makes the panel and all elements not interactable to the mouse, because the scale seems to be not checked in mouse event.

My question is: What are your attempts to achieve a scalable gui?

Before answering zeeeee question. Why not use:

tonegod.gui.controls.extras.SpriteElement

Is this an animated sprite? Or texture atlas?

Reason I ask is, this seems more like a texture issue than a scaling issue,

@t0neg0d said: Before answering zeeeee question. Why not use:

tonegod.gui.controls.extras.SpriteElement

Is this an animated sprite? Or texture atlas?

Reason I ask is, this seems more like a texture issue than a scaling issue,

i use spriteelements, my example was just to explain how i settup the parent. The problem with spriteelement is the wrapparam (Clamp i think)

@b00n said: i use spriteelements, my example was just to explain how i settup the parent. The problem with spriteelement is the wrapparam (Clamp i think)

This should give me enough to test off of. I’ll let you know when I have something.

1 Like

I’d like to bump this, because I’m having similar issues with the mouse interaction on scaled GUI elements.

I’ve noticed a couple of things, but may be doing it wrong:

  1. Scaling affects mouse input. Elements do not behave as expected when scaled. Some controls work, some are at unusual places, and some, like dragging to move, don’t work at all.

  2. Visual elements disappear/change. On the default GUI xml for example, the window title bar vanishes.

Here’s a code example:

[java]
public void configure(MyApplication a)
{
app = a;
screen = new Screen(app, “tonegod/gui/style/atlasdef/style_map.gui.xml”);
screen.setUseTextureAtlas(true,“tonegod/gui/style/atlasdef/atlas.png”);
screen.setUseMultiTouch(true);
app.getGuiNode().addControl(screen);
screen.setUseKeyboardIcons(true);
}

public void makeTestWindow()
{
    Window win = new Window(screen, "win", new Vector2f(0, 0), new Vector2f(400, 400));
    win.setText("I am a window");
    screen.addElement(win);
    
    win.setPosition(0, 100);

    
    float width = win.getWidth();
    ScrollArea scrollArea = new ScrollArea(
        screen,
        "Scroll",
        new Vector2f(15, 40),
        new Vector2f(width-30, 200 ),
        true
    );
    scrollArea.setClippingLayer(scrollArea);
    win.addChild(scrollArea);

    String s = "";
    for (int i=0;i<50;i++) {
        s += "Element " + i + "\n";
    }
    scrollArea.setText(s);
    
    win.setLocalScale(1.0f);
}

[/java]

if I set the very last line, win.setLocalScale(1.1f) the window increases in size as expected, but many things go wrong.
Here’s a screenshot to illustrate.

Imgur

@Trioxin said: I'd like to bump this, because I'm having similar issues with the mouse interaction on scaled GUI elements.

I’ve noticed a couple of things, but may be doing it wrong:

  1. Scaling affects mouse input. Elements do not behave as expected when scaled. Some controls work, some are at unusual places, and some, like dragging to move, don’t work at all.

  2. Visual elements disappear/change. On the default GUI xml for example, the window title bar vanishes.

Here’s a code example:

[java]
public void configure(MyApplication a)
{
app = a;
screen = new Screen(app, “tonegod/gui/style/atlasdef/style_map.gui.xml”);
screen.setUseTextureAtlas(true,“tonegod/gui/style/atlasdef/atlas.png”);
screen.setUseMultiTouch(true);
app.getGuiNode().addControl(screen);
screen.setUseKeyboardIcons(true);
}

public void makeTestWindow()
{
    Window win = new Window(screen, "win", new Vector2f(0, 0), new Vector2f(400, 400));
    win.setText("I am a window");
    screen.addElement(win);
    
    win.setPosition(0, 100);

    
    float width = win.getWidth();
    ScrollArea scrollArea = new ScrollArea(
        screen,
        "Scroll",
        new Vector2f(15, 40),
        new Vector2f(width-30, 200 ),
        true
    );
    scrollArea.setClippingLayer(scrollArea);
    win.addChild(scrollArea);

    String s = "";
    for (int i=0;i<50;i++) {
        s += "Element " + i + "

";
}
scrollArea.setText(s);

    win.setLocalScale(1.0f);
}

[/java]

if I set the very last line, win.setLocalScale(1.1f) the window increases in size as expected, but many things go wrong.
Here’s a screenshot to illustrate.

Imgur

I’ll answer this in the AM more specifically, but you do not want to use setLocalScale(). This is a function of Node, not Element. It can be used in certain circumstances, however… this is not the ideal way to scale a UI. More on this tomorrow.

@t0neg0d said: I'll answer this in the AM more specifically, but you do not want to use setLocalScale(). This is a function of Node, not Element. It can be used in certain circumstances, however... this is not the ideal way to scale a UI. More on this tomorrow.

Thanks for the reply :slight_smile:
I typed this out when I was tired last night. Just to elaborate more:

I tried screen.setGlobalUIScale(x,y)
Which seems to have the desired effect.

However it appears this can only be set once.
Calling,
[java]
screen.setGlobalUIScale(2,2)
screen.setGlobalUIScale(2,2)
screen.setGlobalUIScale(2,2)
[/java]

will result in the UI being resized by (222)

If I call the resize BEFORE adding another element, the element is added at a standard 1.0 scale.

Therefore, I’d have to set my entire GUI up THEN perform scaling, where-as I’d like to be able to add and remove elements dynamically.

Specifically, it is important that interactive elements such as buttons and scroll bars increase in size, as I’m planning to scale based on screen resolution of an android device without having to make many different XMLs for different resolutions.

@Trioxin said: Thanks for the reply :) I typed this out when I was tired last night. Just to elaborate more:

I tried screen.setGlobalUIScale(x,y)
Which seems to have the desired effect.

However it appears this can only be set once.
Calling,
[java]
screen.setGlobalUIScale(2,2)
screen.setGlobalUIScale(2,2)
screen.setGlobalUIScale(2,2)
[/java]

will result in the UI being resized by (222)

If I call the resize BEFORE adding another element, the element is added at a standard 1.0 scale.

Therefore, I’d have to set my entire GUI up THEN perform scaling, where-as I’d like to be able to add and remove elements dynamically.

Specifically, it is important that interactive elements such as buttons and scroll bars increase in size, as I’m planning to scale based on screen resolution of an android device without having to make many different XMLs for different resolutions.

setGlobalUIScale was sort of experimental… and only semi works :wink:

I’m currently doing this for the android app I’m working on. Let me put together an example of how I am scaling the UI. Give me about 30 minutes to wake up, get coffee, etc and I’ll post it.

Ok… here it is:

The first thing you want to do is define a width that you will use as a reference point. In my case I am developing for portrait orientation and picked 480 x 720 as a reference.

Once the screen is created, grab your scale by doing the following:

[java]
float refWidth = 480;
float guiScale = refWidth/screen.getWidth();
[/java]

Now that you have your scale factor, when you create an element, do the following:

[java]
float buttonWidth = 300 * guiScale;
float buttonHeight = 60 * guiScale;
ButtonAdapter ba1 = new ButtonAdapter(screen, UIDUtil.getUID(),
Vector2f.ZERO,
new Vector2f(buttonWidth, buttonHeight)
);
screen.addElement(ba1);
ba1.setPosition(
screen.getWidth()/2-(buttonWidth/2),
screen.getHeight()/2-(buttonHeight/2)
);
[/java]

Another trick is using the pixel width of the ui image… say you have a background image that is a portion of a 1024 x 1024 image (say 1024 x 245) and you need this to fill the top portion of your app. You would:

[java]
float headerScale = screen.getWidth()/1024;
header = new Element(
screen,
“header”,
Vector2f.ZERO,
new Vector2f(1024headerScale,245headerScale),
Vector4f.ZERO,
null
);
header.setTextureAtlasImage(main.getTextureUIAtlas(), main.getUICoords(RegionName.Header));
[/java]

In my case, I need TextElements to accurately display in at certain places in the header image, I chose to use the pixel width in this case, so I could measure out where in the image the text should display and then multiply this by headerScale to have it display in the proper place no matter what device the app is being run on.

Hopefully this is helpful. Do let me know if there are any questions about how I did this.

Also, for the above, I set the position of the button to the center of the screen to show how you might position the element if it were NOT the center of the screen :wink: If it was the center of the parent element, you would just call centerToParent();

One last thing…

I came up with a way of scaling font sizes accurately as well. It is a one-time expensive process and then the scale factor can be used to scale all font sizes.

This works with TexxtElement, asit’s alignment features are more accurate than BitmapText. The general idea would work fine for BitmapText as well, just no guarantees that BitmapText will align correctly at extreme font sizes.

Let me know if you need to do this and I’ll post the method for scaling font size correctly.

@t0neg0d said: Ok... here it is:

[snipped]

How will this affect something like the scroll area, though? On a button that would be sufficient, however the scroll bar is a fixed size irrespective of what I would set the actual scrollArea’s domensions to be.

As suck an 800x480 resolution on a 4 inch screen would get a manageable size, while a 1920x1080 resolution on the same screen with the same XML setup would get a teeny tiny scroll bar that’s super hard to accurately touch.

I am quite liking many aspects of setGlobalUIScale in that respect.
Which aspects of it don’t work? :o

@Trioxin said: How will this affect something like the scroll area, though? On a button that would be sufficient, however the scroll bar is a fixed size irrespective of what I would set the actual scrollArea's domensions to be.

As suck an 800x480 resolution on a 4 inch screen would get a manageable size, while a 1920x1080 resolution on the same screen with the same XML setup would get a teeny tiny scroll bar that’s super hard to accurately touch.

I am quite liking many aspects of setGlobalUIScale in that respect.
Which aspects of it don’t work? :o

Honestly, I do not remember what issues there were with it. It’s been quite a while since I threw it together.

However, I’m trying to make as many of the sub-components of controls accessible as possible. Though, this is sort of an on-going effort. I believe that all of VScrollBar is accessible now and new updates (soonish) will try and account for any controls I have missed thus far.

Let me have a crack at re-implementing global scaling and see if I can get it to work as intended originally.