在 LibGDX/Box2d 中需要帮助缩放屏幕

Need help scaling screen in LibGDX/Box2d

我一直在使用 libGDX 框架为 android/desktop 创建一个简单的游戏。快完成了,但我很难让它适应不同的屏幕比例。我目前正在使用 FitViewport,它可以很好地保持我想要的屏幕比例,但我想这样做,以便顶部和底部的黑条分别为天空和地面着色。我也试过根本不使用视口,然后使用 ShapeRenderer 添加颜色,但它只是拉伸所有艺术以适合屏幕,不使用我想要的屏幕比例,并忽略 ShapeRenderer 形状。

这是我的 GameRenderer class 的构造函数代码:

public GameRenderer (GameWorld gameWorld) {
    this.gameWorld = gameWorld;

    camera = new OrthographicCamera();
    camera.setToOrtho(false, V_WIDTH / PPM, V_HEIGHT / PPM);

    uiCamera = new OrthographicCamera();
    uiCamera.setToOrtho(false, V_WIDTH, V_HEIGHT);

    batch = new SpriteBatch();
    batch.setProjectionMatrix(camera.combined);

    viewport = new FitViewport(V_WIDTH / PPM, V_HEIGHT / PPM, camera);
    viewport.apply();

    shapeRenderer = new ShapeRenderer();
    shapeRenderer.setProjectionMatrix(camera.combined);

    debugRenderer = new Box2DDebugRenderer();
    frog = gameWorld.getFrog();
    jumpRope = gameWorld.getJumpRope();

    score = gameWorld.getScore() + "";
    highScore = AssetLoader.getHighScore() + "";
}

这里是 render() 方法:

    public void render () {
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    score = gameWorld.getScore() + "";
    highScore = AssetLoader.getHighScore() + "";

    batch.begin();
    batch.draw(AssetLoader.background, 0, 0, 236 / PPM, 300 / PPM);

    batch.setProjectionMatrix(uiCamera.combined);
    if (gameWorld.isReady() || gameWorld.isTitleScreen() ) {
        AssetLoader.shadow.getData().setScale(0.4f, 0.4f);
        AssetLoader.shadow.draw(batch, "Tap to start!", 23, V_HEIGHT - 60);

        AssetLoader.font.getData().setScale(0.4f, 0.4f);
        AssetLoader.font.draw(batch, "Tap to start!", 22, V_HEIGHT - 61);
    } else {
        if (gameWorld.isGameOver()) {
            AssetLoader.shadow.getData().setScale(0.4f, 0.4f);
            AssetLoader.shadow.draw(batch, "Game Over", 40, V_HEIGHT - 60);

            AssetLoader.font.getData().setScale(0.4f, 0.4f);
            AssetLoader.font.draw(batch, "Game Over", 39, V_HEIGHT - 61);

            AssetLoader.shadow.draw(batch, "High Score: " + highScore, 15, V_HEIGHT - 90);
            AssetLoader.font.draw(batch, "High Score: " + highScore, 14, V_HEIGHT - 91);
        } else {
            AssetLoader.shadow.getData().setScale(0.55f, 0.55f);
            AssetLoader.shadow.draw(batch, score, (V_WIDTH / 2) - (8 * score.length()), V_HEIGHT / 1.25f);

            AssetLoader.font.getData().setScale(0.55f, 0.55f);
            AssetLoader.font.draw(batch, score, (V_WIDTH / 2) - (8 * score.length()) - 1, V_HEIGHT / 1.25f - 1);
        }
    }

    batch.setProjectionMatrix(camera.combined);

    if (jumpRope.getJumpRopeBehindFrog()) {
        jumpRope.draw(batch);
    }

    if (gameWorld.getFrog().getY() > -60 / PPM) {
        frog.draw(batch);
    }

    if (!jumpRope.getJumpRopeBehindFrog()) {
        jumpRope.draw(batch);
    }

    batch.end();

    debugRenderer.render(gameWorld.getWorld(), camera.combined);

    gameWorld.getWorld().step(1/60f, 6, 2);
}

我的所有游戏玩法和 Box2D 东西都使用主 OrthographicCamera 相机,顾名思义,我对所有 UI 使用 uiCamera。感谢任何和所有帮助!

尝试添加后台后:

    public GameRenderer (GameWorld gameWorld) {
    this.gameWorld = gameWorld;

    camera = new OrthographicCamera();
    camera.setToOrtho(false, V_WIDTH / PPM, V_HEIGHT / PPM);

    uiCamera = new OrthographicCamera();
    uiCamera.setToOrtho(false, V_WIDTH, V_HEIGHT);

    batch = new SpriteBatch();
    batch.setProjectionMatrix(camera.combined);

    // Test code
    backViewport = new ExtendViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

    backStage = new Stage();
    backStage.setViewport(backViewport);
    //

    viewport = new FitViewport(V_WIDTH / PPM, V_HEIGHT / PPM, camera);
    viewport.apply();

    shapeRenderer = new ShapeRenderer();
    shapeRenderer.setProjectionMatrix(camera.combined);

    debugRenderer = new Box2DDebugRenderer();
    frog = gameWorld.getFrog();
    jumpRope = gameWorld.getJumpRope();

    score = gameWorld.getScore() + "";
    highScore = AssetLoader.getHighScore() + "";

    // Test code
    backStage.addActor(new Image(AssetLoader.backgroundColor));
}

public void render () {
    Gdx.gl.glClearColor(0, 0, 0, 1);
    Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

    score = gameWorld.getScore() + "";
    highScore = AssetLoader.getHighScore() + "";

    batch.begin();
    batch.draw(AssetLoader.background, 0, 0, 236 / PPM, 300 / PPM);

    batch.setProjectionMatrix(uiCamera.combined);
    if (gameWorld.isReady() || gameWorld.isTitleScreen() ) {
        AssetLoader.shadow.getData().setScale(0.4f, 0.4f);
        AssetLoader.shadow.draw(batch, "Tap to start!", 23, V_HEIGHT - 60);

        AssetLoader.font.getData().setScale(0.4f, 0.4f);
        AssetLoader.font.draw(batch, "Tap to start!", 22, V_HEIGHT - 61);
    } else {
        if (gameWorld.isGameOver()) {
            AssetLoader.shadow.getData().setScale(0.4f, 0.4f);
            AssetLoader.shadow.draw(batch, "Game Over", 40, V_HEIGHT - 60);

            AssetLoader.font.getData().setScale(0.4f, 0.4f);
            AssetLoader.font.draw(batch, "Game Over", 39, V_HEIGHT - 61);

            AssetLoader.shadow.draw(batch, "High Score: " + highScore, 15, V_HEIGHT - 90);
            AssetLoader.font.draw(batch, "High Score: " + highScore, 14, V_HEIGHT - 91);
        } else {
            AssetLoader.shadow.getData().setScale(0.55f, 0.55f);
            AssetLoader.shadow.draw(batch, score, (V_WIDTH / 2) - (8 * score.length()), V_HEIGHT / 1.25f);

            AssetLoader.font.getData().setScale(0.55f, 0.55f);
            AssetLoader.font.draw(batch, score, (V_WIDTH / 2) - (8 * score.length()) - 1, V_HEIGHT / 1.25f - 1);
        }
    }

    batch.setProjectionMatrix(camera.combined);

    if (jumpRope.getJumpRopeBehindFrog()) {
        jumpRope.draw(batch);
    }

    if (gameWorld.getFrog().getY() > -60 / PPM) {
        frog.draw(batch);
    }

    if (!jumpRope.getJumpRopeBehindFrog()) {
        jumpRope.draw(batch);
    }

    batch.end();

    // I put this in front of everything so that I could see what it's doing
    backStage.act();
    backStage.draw();
    //

    debugRenderer.render(gameWorld.getWorld(), camera.combined);

    gameWorld.getWorld().step(1/60f, 6, 2);
}

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

引自Libgdx wiki

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.

viewport1.apply();
// draw
viewport2.apply();
// draw

When using multiple Stages:

stage1.getViewport().apply();
stage1.draw();
stage2.getViewport().apply();
stage2.draw();

更新。一些与您的问题无关的注释:

  • 对资产使用静态引用(如代码中的 AssetLoader.background)通常被认为是一种不好的做法。例如,阅读这些:,

  • SpriteBatches 是重对象,所以最好只有一个 SpriteBatch 实例并共享它:

    backStage = new Stage(backViewport, batch);