Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deal with different aspect ratios in libGDX?

I have implemented some screens using libGDX that would obviously use the Screen class provided by the libGDX framework. However, the implementation for these screens works only with pre-defined screen sizes. For example, if the sprite was meant for a 640 x 480 size screen (4:3 Aspect ratio), it won't work as intended on other screen sizes because the sprites go par the screen boundaries and are not scaled to the screen size at all. Moreover, if simple scaling would have been provided by the libGDX, the issue I am facing would have still been there because that would cause the aspect ratio of the game screen to change.

After researching on internet, I came across a blog/forum that had discussed the same issue. I have implemented it and so far it is working fine. But I want to confirm whether this is the best option to achieve this or whether there are better alternatives. Below is the code to show how I am dealing with this legitimate problem.

FORUM LINK: http://www.java-gaming.org/index.php?topic=25685.new

public class SplashScreen implements Screen {      // Aspect Ratio maintenance     private static final int VIRTUAL_WIDTH = 640;     private static final int VIRTUAL_HEIGHT = 480;     private static final float ASPECT_RATIO = (float) VIRTUAL_WIDTH / (float) VIRTUAL_HEIGHT;      private Camera camera;     private Rectangle viewport;     // ------end------      MainGame TempMainGame;      public Texture splashScreen;     public TextureRegion splashScreenRegion;     public SpriteBatch splashScreenSprite;      public SplashScreen(MainGame maingame) {         TempMainGame = maingame;     }      @Override     public void dispose() {         splashScreenSprite.dispose();         splashScreen.dispose();     }      @Override     public void render(float arg0) {         //----Aspect Ratio maintenance          // update camera         camera.update();         camera.apply(Gdx.gl10);          // set viewport         Gdx.gl.glViewport((int) viewport.x, (int) viewport.y,         (int) viewport.width, (int) viewport.height);          // clear previous frame         Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);          // DRAW EVERYTHING         //--maintenance end--          splashScreenSprite.begin();         splashScreenSprite.disableBlending();         splashScreenSprite.draw(splashScreenRegion, 0, 0);         splashScreenSprite.end();     }      @Override     public void resize(int width, int height) {         //--Aspect Ratio Maintenance--         // calculate new viewport         float aspectRatio = (float)width/(float)height;         float scale = 1f;         Vector2 crop = new Vector2(0f, 0f);          if(aspectRatio > ASPECT_RATIO) {             scale = (float) height / (float) VIRTUAL_HEIGHT;             crop.x = (width - VIRTUAL_WIDTH * scale) / 2f;         } else if(aspectRatio < ASPECT_RATIO) {             scale = (float) width / (float) VIRTUAL_WIDTH;             crop.y = (height - VIRTUAL_HEIGHT * scale) / 2f;         } else {             scale = (float) width / (float) VIRTUAL_WIDTH;         }          float w = (float) VIRTUAL_WIDTH * scale;         float h = (float) VIRTUAL_HEIGHT * scale;         viewport = new Rectangle(crop.x, crop.y, w, h);         //Maintenance ends here--     }      @Override     public void show() {         camera = new OrthographicCamera(VIRTUAL_WIDTH, VIRTUAL_HEIGHT); //Aspect Ratio Maintenance          splashScreen = new Texture(Gdx.files.internal("images/splashScreen.png"));         splashScreenRegion = new TextureRegion(splashScreen, 0, 0, 640, 480);         splashScreenSprite = new SpriteBatch();          if(Assets.load()) {             this.dispose();             TempMainGame.setScreen(TempMainGame.mainmenu);         }     } } 

UPDATE: I recently came to know that libGDX has some of its own functionality to maintain aspect ratios which I would like to discuss here. While searching the aspect ratio issue across the internet, I came across several forums/developers who had this problem of "How to maintain the aspect ratio on different screen sizes?" One of the solutions that really worked for me was posted above.

Later on when I proceeded with implementing the touchDown() methods for the screen, I found that due to scaling on resize, the co-ordinates on which I had implemented touchDown() would change by a great amount. After working with some code to translate the co-ordinates in accordance with the screen resize, I reduced this amount to a great extent but I wasn't successful to maintain them with pin point accuracy. For example, if I had implemented touchDown() on a texture, resizing the screen would shift the touchListener on the texture region some pixels to the right or left, depending on the resize and this was obviously undesired.

Later on I came to know that the stage class has its own native functionality to maintain the aspect ratio (boolean stretch = false). Now that I have implemented my screen by using the stage class, the aspect ratio is maintained well by it. However on resize or different screen sizes, the black area that is generated always appears on the right side of the screen; that is the screen is not centered which makes it quite ugly if the black area is substantially large.

Can any community member help me out to resolve this problem?

like image 839
Rafay Avatar asked Feb 08 '12 18:02

Rafay


2 Answers

How to do it nowadays:

Since this is one of the most famous questions on libgdx here, I'll give it a little update:

LibGDX v1.0 introduced Viewport to handle this problem. It is a lot easier to use and the scaling strategy is pluggable, which means a single line can change the behaviour and you can play with it and see which one fits your game the best.

Everything you need to know about it can be found here.

like image 156
noone Avatar answered Sep 18 '22 21:09

noone


EDIT: libGDX has evolved. Best answer is now this one by user noone. Be sure to check the link to the Viewport documentation..

As SteveBlack posted the link of the issue that was reported in the stage class, I went there just to discover that the issue (that was not actually my issue) has been resolved in the latest nightlies.

After researching here and there on the internet for the issue I was having, I couldn't find any solutions so decided to contact the person who reported the bug directly. After that, he replied me on libgdx forums and I am indebted to him for his helping me out. Here is the link

It was a single line of code and all you have to do is:

In the resize() methond:

stage.setViewport(640, 480, false); stage.getCamera().position.set(640/2, 480/2, 0); 

Where 640 X 480 is the resolution of your TextureRegion that describes the intended aspect ratio. If your TextureRegion size was 320 X 240, then both the arguments should be changed to the new resolution to do the trick.

Profile link of the original person who actually resolved my issue

like image 40
Rafay Avatar answered Sep 19 '22 21:09

Rafay