1

I am new to the libgdx framework trying to make a game but the problem here is I don't know how to scale the ImageButton for different screen sizes it looks big on desktop but looking small on the android devices. I am using several ImageButtons of different sizes and using table to organize them. Can anyone please make some code changes so I could understand how to scale the images here with the viewports?

public class BabyPhone extends Game {

public static final int WIDTH = 480;
public static final int HEIGHT = 800;

public void create () {


    bg = new BabyActor();
    bg.setTexture(new Texture("background-orange.png"));
    bg.setSize(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());


    phone = new BabyActor();
    phone.setTexture(new Texture("blue-phone.png"));
    phone.setSize(Gdx.graphics.getWidth(),Gdx.graphics.getHeight());


    TextureRegion btLeft = new TextureRegion(new Texture("10OFF.png"));
    Drawable drawableLeft = new TextureRegionDrawable(new TextureRegion(btLeft));
    buttonLeft = new ImageButton(drawableLeft);

    TextureRegion btRight = new TextureRegion(new Texture("12OFF.png"));
    Drawable drawableRight = new TextureRegionDrawable(new TextureRegion(btRight));
    buttonRight = new ImageButton(drawableRight);

    TextureRegion btCenter = new TextureRegion(new Texture("11OFF.png"));
    Drawable drawableCenter = new TextureRegionDrawable(new TextureRegion(btCenter));
    buttonCenter = new ImageButton(drawableCenter);

    TextureRegion bt1 = new TextureRegion(new Texture("1OFF.png"));
    Drawable drawable = new TextureRegionDrawable(new TextureRegion(bt1));
    button1 = new ImageButton(drawable);

    TextureRegion bt2 = new TextureRegion(new Texture("2OFF.png"));
    Drawable drawable1 = new TextureRegionDrawable(new TextureRegion(bt2));
    button2 = new ImageButton(drawable1);

    TextureRegion bt3 = new TextureRegion(new Texture("3OFF.png"));
    Drawable drawable2 = new TextureRegionDrawable(new TextureRegion(bt3));
    button3 = new ImageButton(drawable2);

    TextureRegion bt4 = new TextureRegion(new Texture("4OFF.png"));
    Drawable drawable3 = new TextureRegionDrawable(new TextureRegion(bt4));
    button4 = new ImageButton(drawable3);

    TextureRegion bt5 = new TextureRegion(new Texture("5OFF.png"));
    Drawable drawable4 = new TextureRegionDrawable(new TextureRegion(bt5));
    button5 = new ImageButton(drawable4);

    TextureRegion bt6 = new TextureRegion(new Texture("6OFF.png"));
    Drawable drawable5 = new TextureRegionDrawable(new TextureRegion(bt6));
    button6 = new ImageButton(drawable5);

    TextureRegion bt7 = new TextureRegion(new Texture("7OFF.png"));
    Drawable drawable6 = new TextureRegionDrawable(new TextureRegion(bt7));
    button7 = new ImageButton(drawable6);

    TextureRegion bt8 = new TextureRegion(new Texture("8OFF.png"));
    Drawable drawable7 = new TextureRegionDrawable(new TextureRegion(bt8));
    button8 = new ImageButton(drawable7);

    TextureRegion bt9 = new TextureRegion(new Texture("9OFF.png"));
    Drawable drawable8 = new TextureRegionDrawable(new TextureRegion(bt9));
    button9 = new ImageButton(drawable8);


    gamecam = new OrthographicCamera(WIDTH,HEIGHT);
    gamecam.position.set(WIDTH/2,HEIGHT/2,0);
    gamePort = new ScreenViewport(gamecam);
    backStage = new Stage(gamePort);
    fitPort = new FitViewport(gamecam.viewportWidth,gamecam.viewportHeight,gamecam);
    frontStage = new Stage(fitPort);
    backStage.addActor(bg);
    frontStage.addActor(phone);

    Table table = new Table();
    table.padLeft(40);
    table.setPosition(phone.getWidth()/2,phone.getHeight()/2*0.6f);
    table.row().size(95,95);
    table.add(buttonLeft);
    table.add(buttonCenter);
    table.add(buttonRight);
    table.row().size(95,95);
    table.add(button1);
    table.add(button2);
    table.add(button3);
    table.row().size(95,95);
    table.add(button4);
    table.add(button5);
    table.add(button6);
    table.row().size(95,95);
    table.add(button7);
    table.add(button8);
    table.add(button9);

    frontStage.addActor(table);


}
public void render(){

    backStage.act(Gdx.graphics.getDeltaTime());
    frontStage.act(Gdx.graphics.getDeltaTime());
    backStage.draw();
    frontStage.draw();


}

@Override
public void resize(int width, int height) {
    gamePort.update(width, height);
    frontStage.getViewport().update(width, height);

}

enter image description here

danish
  • 187
  • 1
  • 1
  • 14
  • Why you use two stages? Try to use one Stage with an ExtendViewport and then you make the Background image bigger than the Size of the Viewport. So if someone has a Screen with a higher ratio different they will see a little bit more of the Background but the ratio of your Buttons will be still the same – Morchul Mar 27 '19 at 07:56

2 Answers2

2

I'm just setting it as a percentage of a device size. It's loks like this.

float BUTTON_SIZE = 0.1f;
table.add(button2).size(Gdx.graphics.getWidth()*BUTTON_SIZE,Gdx.graphics.getWidth()*BUTTON_SIZE);
Stanislav Batura
  • 420
  • 4
  • 11
  • I wanted to ask why it is showing padding between all buttons? – danish Mar 24 '19 at 11:01
  • This won't work if you want that the ratio of width and height will be the same on different devices. On a device with size: 200:100 the Button will have a ratio of 2:1 on a Device with 500:100 the button have a ratio of 5:1. – Morchul Mar 25 '19 at 08:22
  • Yup, it's not an universal decision but mostly you have one Main direction and if you scale on it this way it looks good for me – Stanislav Batura Apr 09 '20 at 05:38
1

If you want to use a Viewport you must choose which Viewport you will use.

ScreenViewport

The ScreenViewport will always fill the whole Screen and will stretch your Textures etc. to the Fullscreen.

FitViewport

The FitViewport will not stretch your Textures it will look that the ratio between width and height will always be the same. This Viewport will produce Sidebars on the sides if the Screen doesn't match the defined ratio. So the shorter side will match the screen.

FillViewport

The FillViewport will not stretch your Textures it will look that the ratio between width and height will always be the same. This Viewport does not create Sidebars like FitViewport because it will match the longer side to the screen. So it can happen that something is cut off.

More Viewports: https://github.com/libgdx/libgdx/wiki/Viewports

In my Example, I will use FitViewport.

To use a FitViewport we must create a Camera. We create an OrthographicCamera. With this Camera, we can define the Virtual width and height of our Viewport so the width and height of what we can see.

Camera camera = new OrthographicCamera(100,100);

Now it's important that you think in this virtual size we defined and not in pixels. So we have a size of 100 x 100 units.

Now let's create our FitViewport with our Camera:

FitViewport viewport = new FitViewport(camera.viewportWidth, camera.viewportHeight, camera);

And finally create our Stage with the Viewport:

Stage stage = new Stage(viewport);

So if we now add our buttons to the table we can define the Size of the Buttons in our Virtual size.

So if we add our Button like this:

table.add(button1).size(10,10);

The Button will always be 10% of the Screen because the Button is 10 units big in a world of 100 units

The advantage now of FitViewport is: we defined the Button to be 10x10 so a Ratio of 1:1, a square. If we now resize the Screen or have a different Screen size the Button will always be a square and will always fill 10 of 100 units of the Screen.

This will maybe be a little bit confusing with Virtual size. If you will read more about it, here is a little bit better description: How Camera works in Libgdx and together with Viewport

One more thing we must do before the Viewport works perfectly.

We must update the Viewport in the resize method:

@Override
public void resize(int width, int height) {
    viewport.update(width, height);
}

I hope this will help you to work with Viewports.


You have written that you are new to LibGdx so I will give you some additional suggestions.

This won't work:

Gdx.input.setInputProcessor(stage);
Gdx.input.setInputProcessor(stage1);

Gdx.input can only hold one InputProcessor per time so stage1 will override stage. If you will use more than one InputProcessor use InputMultiplexer: https://github.com/libgdx/libgdx/wiki/Event-handling

If you use a Table and every actor in a row have for example the same size. Instead of writing by every actor: table.add(button1).size(10,10);
Table has a special feature, if you set something to row() this will apply to all Actors in this row.

So instead of writing this:

table.add(button1).size(10,10);
table.add(button2).size(10,10);
table.add(button3).size(10,10);
table.row();
table.add(button4).size(10,10);
table.add(button5).size(10,10);
table.add(button6).size(10,10);

You can write this:

table.row().size(10,10);
table.add(button1);
table.add(button2);
table.add(button3);
table.row().size(10,10);
table.add(button4);
table.add(button5);
table.add(button6);

I hope these little suggestions will help you.

Morchul
  • 1,987
  • 1
  • 7
  • 21
  • I am using fitviewport now but the background showing black lines on both sides. Should i use screen viewport with background? – danish Mar 25 '19 at 16:40
  • Now i am using extendviewport still the background image not covering the entire backround and black lines also appearing. – danish Mar 25 '19 at 17:25
  • @danish FitViewport shows Black lines on the side because the Viewport cuts the screen so you have always the same ratio between width and height. Extendviewport makes the same like FitViewport except he doesn't cut the screen. He extends the Screen, so on screens with bigger width and height ratio you will see more. ExtendViewport should not create Black bars except you define a Maximum. Which Constructor of ExtendViewport do you use? – Morchul Mar 26 '19 at 07:57
  • I am updating my question with code and image, please check it – danish Mar 27 '19 at 03:50