When dealing with different screens it is often necessary to decide for a certain strategy how those different screen sizes and aspect ratios should be handled. Camera and Stage support different viewport strategies, for example when doing picking via Camera.project(vec, viewportX, viewportY, viewportWidth, viewportHeight).

libGDX provides a more convenient way of dealing with this problem: Viewport (source).

Usage

A viewport always manages a Camera’s viewportWidth and viewportHeight. Thus a camera needs to be supplied to the constructors.

  1. private Viewport viewport;
  2. private Camera camera;
  3. public void create() {
  4. camera = new PerspectiveCamera();
  5. viewport = new FitViewport(800, 480, camera);
  6. }

Whenever a resize event occurs, the viewport needs to be informed about it and updated. This will automatically recalculate the viewport parameters and update the camera:

  1. public void resize(int width, int height) {
  2. viewport.update(width, height);
  3. }

Furthermore it will change the OpenGL Viewport via glViewport, which may add black bars if necessary, making it impossible to render in the area of the black bars. In case black bars appear with a certain viewport strategy, the OpenGL viewport may be reset to its standard size and the viewport can be queried for the size of the bars via Viewport.getLeftGutterWidth() etc. For an example of how to do so, see this test. This might look like the following (probably with a more appropriate border picture…)

Viewports - 图1

In case picking needs to be done, Viewport offers convenient project/unproject/getPickRay methods, which uses the current viewport to do the correct picking. This is how you convert to and from screen and world coordinates.

When Stage is used, the Stage’s viewport needs to be updated when a resize event happens.

  1. private Stage stage;
  2. public void create() {
  3. stage = new Stage(new StretchViewport(width, height));
  4. }
  5. public void resize(int width, int height) {
  6. // use true here to center the camera
  7. // that's what you probably want in case of a UI
  8. stage.getViewport().update(width, height, true);
  9. }

Multiple viewports

When using multiple viewports that have different screen sizes (or you use other code that sets glViewport), you will need to apply the viewport before drawing so the glViewport is set for that viewport.

  1. viewport1.apply();
  2. // draw
  3. viewport2.apply();
  4. // draw

When using multiple Stages:

  1. stage1.getViewport().apply();
  2. stage1.draw();
  3. stage2.getViewport().apply();
  4. stage2.draw();

Examples

To see the viewports in action, have a look at this interactive example. There are also some tests concerning viewports: ViewportTest1, ViewportTest2 and ViewportTest3.

StretchViewport

The StretchViewport (source) supports working with a virtual screen size. That means one can assume that a screen is always of the size virtualWidth x virtualHeight. This virtual viewport will then always be stretched to fit the screen. There are no black bars, but the aspect ratio may not be the same after the scaling took place.

Viewports - 图2

FitViewport

A FitViewport (source) also supports a virtual screen size. The difference to StretchViewport is that it will always maintain the aspect ratio of the virtual screen size (virtual viewport), while scaling it as much as possible to fit the screen. One disadvantage with this strategy is that there may appear black bars.

Viewports - 图3

FillViewport

A FillViewport (source) also keeps the aspect ratio of the virtual screen size, but in contrast to FitViewport, it will always fill the whole screen which might result in parts of the viewport being cut off.

ScreenViewport

The ScreenViewport (source) does not have a constant virtual screen size; it will always match the window size which means that no scaling happens and no black bars appear. As a disadvantage this means that the gameplay might change, because a player with a bigger screen might see more of the game, than a player with a smaller screen size.

Viewports - 图4

ExtendViewport

The ExtendViewport (source) keeps the world aspect ratio without black bars by extending the world in one direction. The world is first scaled to fit within the viewport, then the shorter dimension is lengthened to fill the viewport.

Viewports - 图5

A maximum set of dimensions can be supplied to ExtendViewport, in which case, black bars will be added when the aspect ratio falls out of the supported range.

Viewports - 图6

CustomViewport

Different strategies may be implemented by doing CustomViewport extends Viewport and overriding update(width, height, centerCamera). Another approach is use the generic ScalingViewport and supplying another Scaling which is not yet covered by any other Viewport. One example could be to supply Scaling.none to it, which will result in a completely “StaticViewport”, which always keeps the same size. It might look like this:

Viewports - 图7