简体   繁体   中英

LibGdx - Scaling Sprites, Camera and Viewports

Hell All & thanks for reading,

I recently started working on an 2D Android/Desktop project and have become stuck trying to display my sprites in the way i want.

I have a background Sprite that is 144(w) by 160(h) that I want to be able to position other sprites onto the screen relative to points on the background sprite.

I think I understand that if I create a camera/viewport that is 144 x 160 I would be able to position my sprites on the background sprite using the co-ordinates based on the 144 x 160 of the background sprite. This will work across the different screen resolutions found on mobile devices but will stretch the background sprite despite experimenting with the different viewport types (FillViewport, FitViewport etc..).

What I want to achieve is to have my background sprite to maintain it ratio across different screen resolutions and to be able to place other sprites over the background sprite. The placing of sprite need to work across different resolutions.

Apologies if my explanation is confusing or makes no sense. I would add some image to help explain but I reputation to add any to the post. However I think the TLTR question is "What is the correct way to display sprites on multiple screen resolutions while keeping a correct ratios and scaling to the screen size and position of sprite in a way that works across multiple resolutions?"

Thank, All Questions Welcome

A FitViewport would do what you described (maintain aspect ratio), but you will have black bars on some devices. Based on the code you posted on the libgdx forum, I see that you forgot to update the viewport in the resize method, so it is not behaving as designed.

However, for a static camera game like what you described, I think the best solution would be to plan your game around a certain area that is always visible on any device, for example, the box from (0,0) to (144,160). Then use an ExtendViewport with width and height of 144 and 160. After you update the viewport in resize , you can move the camera to be centered on the rectangle like this:

private static final float GAME_WIDTH = 144;
private static final float GAME_HEIGHT = 160;

public void create(){
    //...
    viewport = new ExtendViewport(GAME_WIDTH, GAME_HEIGHT);
    //...
}

public void resize(int width, int height){
    viewport.update(width, height, false); //centering by putting true here would put (0,0) at bottom left of screen, but then the game rectangle would be off center

    //manually center the center of your game box
    Camera camera = viewport.getCamera();
    camera.position.x = GAME_WIDTH /2;
    camera.position.y = GAME_HEIGHT/2;
    camera.update();
}

Now your 144x160 box is centered on the screen as it would be with FitViewport, but you are not locked into having black bars, because you can draw extra background outside the 144x160 area using whatever method you like.

In your case 144:160 is a wider portrait aspect ratio than any screen out there, so you wouldn't need to worry about ever filling in area to the sides of your game rectangle. The narrowest aspect ratio of any phone or tablet seems to be 9:16, so you can do the math to see how much extra background above and below the game rectangle should be drawn to avoid black showing through on any device.

In this case it works out to 48 units above and below the rectangle that you would want to fill in:

  • 144 pixels wide at 9:16 would be 256 tall.
  • (256 - 160) / 2 = 48

EDIT: I see from your post on the libgdx forum that you want the game area stuck at the top of the screen and the remainder of the area to be used for game controls. In that case, I would change the resize method like this, since you want to have the game area's top edge aligned with the top edge of the screen. You can also calculate where the bottom of the controls area will be on the Y axis. (The top will be at Y=0.)

public void resize(int width, int height){
    viewport.update(width, height, false); 

    //align game box's top edge to top of screen
    Camera camera = viewport.getCamera();
    camera.position.x = GAME_WIDTH /2;
    camera.position.y = GAME_HEIGHT - viewport.getWorldHeight()/2;
    camera.update();

    controlsBottomY = GAME_HEIGHT - viewport.getWorldHeight();
}

I'm not sure how you plan to do your controls, but they would need to fit in the box (0, controlsBottomY) to (GAME_WIDTH, 0) . Keep in mind that there are some phones with aspect ratios as small as 3:4 (although rare now). So with your 0.9 aspect ratio, on a 3:4 phone only the bottom 17% of the screen would be available for controls. Which might be fine if it's just a couple of buttons, but would probably be problematic if you have a virtual joystick.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM