Search code examples
javaandroidlibgdxbox2dscene2d

Scaling between different devices on LibGdx Box2d and Scene2d


I am working with LibGdx using Scene2d and Box2d. I designed 2 Stages using Scene2D. One stage is for GUI, for example buttons, the second one contains Actors with Images that are pinned to my Box2d Object coordinates(in my case simple rectangles):

When I run the game on PC I get the following image: enter image description here

When I run it on my Galaxy S9+ I receive the following image:

enter image description here

As you can see, the background and box2d objects all scale properly on PC and on Android. The problem is that my Actor images are displaced on PC compared to Android(The cowboy images). I scaled Box2D to have better physics, but since then Im having trouble scaling objects cross platform.

Code:

    //My base screen, other screens extend this one:
    public BaseScreen(){
    Box2D.init();

    mainStage = new Stage();
    uiStage = new Stage();

    manager = new AssetManager();

    debug= new Box2DDebugRenderer();

    world = new World(new Vector2(0,0),false);

    loadAssetmanager();

    //Box2d Sprites are initialzed in here:
    initialize();

    camera= new OrthographicCamera();
    camera.setToOrtho(false,1024,1024);

    debugMatrix= camera.combined.cpy();
    debugMatrix.scale(32,32,0);
    mainStage.getViewport().setCamera(camera);
    camera.update();

    //This BaseScreen class will initialize all assets from its subclasses here.

    setMultiplexer();

    }

Background: I am a medical resident, self taught in Java. I am trying to design a small simulation for my medical students and I want them to be able to have access to it on their PCs, phones or tablets. I need basic Box2D physics(I dont have time to program my own physics engine while working 40-70 hour weeks), so LibGdx and Box2d is the ideal framework for me. Any input would be much appreciated.


Solution

  • I found the solution. After stepping back for a day and not touching the computer I came back with a fresh perspective. I re-read the wikipedia page concering Viewports and finally got it: https://github.com/libgdx/libgdx/wiki/Viewports

    Its a simple one. I initialized my mainStage() and did not pass a viewport to it. So LibGdx creates its own default Viewport. When I looked at the source code for the Stage() class constructor inside LibGdx I found that the default Viewport is a ScalingViewport set to Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), this reads every device width/heigh and scales it differently:

        /** Creates a stage with a {@link ScalingViewport} set to {@link 
            Scaling#stretch}. The stage will use its own {@link Batch}
        *   which will be disposed when the stage is disposed. */
     public Stage () {
        this(new ScalingViewport(Scaling.stretch, Gdx.graphics.getWidth(), 
        Gdx.graphics.getHeight(), new OrthographicCamera()), new SpriteBatch());
        ownsBatch = true;
      }
    

    So to fix the problem I changed the following code, instead of:

    mainStage = new Stage();
    

    I changed the code to, so that every device will scale to the same width/height:

     mainStage = new Stage(new StretchViewport(1024,1024));
    

    This change basically sets the viewport to be 1024x1024 Pixels and will now be properly scaled on my PC, on the Galaxy S9+/other devices.