我试图理解 libgdx 中具有多个视口的行为,这似乎是不可预测的

问题描述 投票:0回答:1

我一直在努力放置两个小视口,主视口占用整个屏幕空间,次要视口位于右上角(因为我们的想法是在那里绘制 FPS 计数器)

问题是我无法理解它到底是如何工作的,我一直在与人工智能交谈,经过一些更改后视口就可以工作了......但我需要理解为什么我的第一个实现不起作用,因为AI的答案很糟糕“有时你只需要使用手动视口放置,因为有时setScreenPosition可能无法按预期工作”

不工作的代码:

public class TestViewportGame extends Game {
    private SpriteBatch batch;
    private OrthographicCamera mainCamera;
    private OrthographicCamera smallCamera;
    private Viewport mainViewport;
    private Viewport smallViewport;
    private ShapeDrawerHack shapeDrawerHack;

    @Override
    public void create() {
        batch = new SpriteBatch();

        // Main camera setup
        mainCamera = new OrthographicCamera();
        mainViewport = new FitViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), mainCamera);
        mainViewport.apply();
        mainCamera.position.set(mainViewport.getWorldWidth() / 2, mainViewport.getWorldHeight() / 2, 0);
        mainCamera.update();

        // Small camera setup
        smallCamera = new OrthographicCamera();
        smallViewport = new FitViewport(200, 150, smallCamera);
        smallViewport.setScreenPosition(Gdx.graphics.getWidth() - 200, Gdx.graphics.getHeight() - 150);
        smallViewport.apply();
        smallCamera.position.set(smallViewport.getWorldWidth() / 2, smallViewport.getWorldHeight() / 2, 0);
        smallCamera.update();

        // Initialize ShapeDrawer
        shapeDrawerHack = new ShapeDrawerHack(new ShapeDrawer(batch));
        shapeDrawerHack.load();
    }

    @Override
    public void render() {
        ScreenUtils.clear(Color.BLACK);

        // Render main scene
        mainViewport.apply();
        mainCamera.update();
        batch.setProjectionMatrix(mainCamera.combined);
        batch.begin();
        // Draw main scene elements here
        batch.end();

        // Render small viewport
        smallViewport.apply();
        smallCamera.update();
        batch.setProjectionMatrix(smallCamera.combined);
        batch.begin();
        shapeDrawerHack.getShapeDrawer().filledRectangle(0, 0, smallViewport.getWorldWidth(), smallViewport.getWorldHeight(), Color.RED);
        batch.end();
    }

    @Override
    public void resize(int width, int height) {
        mainViewport.update(width, height);
        smallViewport.update(width, height);
    }

    @Override
    public void dispose() {
        batch.dispose();
        shapeDrawerHack.dispose();
    }
}

工作代码:

public class TestGame extends Game {
    private SpriteBatch batch;
    private OrthographicCamera mainCamera;
    private OrthographicCamera smallCamera;
    private Viewport mainViewport;
    private Viewport smallViewport;
    private ShapeDrawerHack shapeDrawerHack;

    @Override
    public void create() {
        batch = new SpriteBatch();

        // Main camera setup
        mainCamera = new OrthographicCamera();
        mainViewport = new FitViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), mainCamera);
        mainViewport.apply();
        mainCamera.position.set(mainViewport.getWorldWidth() / 2, mainViewport.getWorldHeight() / 2, 0);
        mainCamera.update();

        // Small camera setup
        smallCamera = new OrthographicCamera();
        smallViewport = new FitViewport(200, 150, smallCamera);
        smallCamera.position.set(smallViewport.getWorldWidth() / 2, smallViewport.getWorldHeight() / 2, 0);
        smallCamera.update();

        // Initialize ShapeDrawer
        shapeDrawerHack = new ShapeDrawerHack(new ShapeDrawer(batch));
        shapeDrawerHack.load();
    }

    @Override
    public void render() {
        ScreenUtils.clear(Color.BLACK);

        // Render main scene
        mainViewport.apply();
        mainCamera.update();
        batch.setProjectionMatrix(mainCamera.combined);
        batch.begin();
        // Draw main scene elements here
        batch.end();

        // Render small viewport
        Gdx.gl.glViewport(Gdx.graphics.getWidth() - 200, Gdx.graphics.getHeight() - 150, 200, 150);
        smallCamera.update();
        batch.setProjectionMatrix(smallCamera.combined);
        batch.begin();
        shapeDrawerHack.getShapeDrawer().filledRectangle(0, 0, smallViewport.getWorldWidth(), smallViewport.getWorldHeight(), Color.RED);
        batch.end();

        // Reset viewport to main camera
        Gdx.gl.glViewport(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    }

    @Override
    public void resize(int width, int height) {
        mainViewport.update(width, height);
        smallViewport.update(width, height);
    }

    @Override
    public void dispose() {
        batch.dispose();
        shapeDrawerHack.dispose();
    }
}

注意事项:

  • 唯一的区别是使用手动视口定位,而不是使用viewPort apply方法
  • 唯一的自定义类是 ShapeDrawerHack,它只是 ShapeDrawer 纹理加载和处理的包装器

提前致谢!

libgdx
1个回答
0
投票

libGDX 中,处理多个视口确实看起来不可预测,特别是在管理具有自己的摄像机和视口的不同阶段或场景时。让我们详细分析一下视口的工作原理以及使用多个视口时可能导致不可预测行为的原因。

libGDX 中视口的关键概念

  1. 视口类型:libGDX 提供了多种类型的视口(

    ScreenViewport
    FitViewport
    FillViewport
    StretchViewport
    ExtendViewport
    ScalingViewport
    )。其中每一个都有不同的策略来处理调整大小和缩放,这可能会影响事物的显示方式。

  2. 视口和相机的关系:视口链接到相机。当您创建视口时,它会根据屏幕尺寸和所选的缩放策略来管理相机的视口尺寸。

  3. 处理多个视口:当您有多个视口时,每个视口都与不同的阶段或渲染通道相关联,需要仔细处理它们各自的相机更新。

不可预测行为的常见原因

  1. 视口更新不当

    • 当窗口或屏幕尺寸发生变化时,每个视口都需要更新。这通常是通过在
      viewport.update(width, height)
      resize()
      ApplicationListener
      方法中调用
      Screen
      来完成。
  2. 冲突的视口:

    • 如果您有多个视口,请确保每个视口都正确更新和渲染,而不会相互干扰。例如,设置批次的投影矩阵需要与视口的相机相匹配。
  3. 相机配置不正确

    • 有时,视口的相机可能配置不正确,导致未对准或意外缩放。确保相机位置正确且其设置(如变焦和位置)适当。
  4. 操作顺序

    • 渲染不同视口及其阶段的顺序至关重要。如果阶段以不正确的顺序渲染或没有正确清除屏幕,一个阶段可能会意外地渲染在另一个阶段上。
  5. 视口特定问题

    • 某些视口(如
      FillViewport
      StretchViewport
      )在不同的屏幕宽高比下可能表现不同,可能导致看似不可预测的剪切或拉伸。使用
      FitViewport
      可以帮助保持宽高比,但会增加黑条,而
      StretchViewport
      可能会扭曲宽高比以适合屏幕。

使用多个视口的最佳实践

  1. 持续更新

    • 确保使用当前屏幕宽度和高度在
      update()
      方法中的每个视口上调用
      resize()
  2. 渲染顺序和清屏:

    • 在渲染过程开始时清除屏幕一次 (
      Gdx.gl.glClear(...)
      )。然后,按预期顺序渲染每个视口/阶段。
  3. 每个视口单独批次

    • 如果您使用多个
      Stage
      对象或使用不同视口进行自定义渲染,请确保每个阶段都有自己的
      SpriteBatch
      或至少在渲染每个阶段之前正确设置投影矩阵。
  4. 调试视口状态:

    • 使用
      ShapeRenderer
      等调试工具来绘制视口和相机的边界。这可以帮助识别错位或缩放问题。
  5. 记录和逐步验证

    • 在调整大小或渲染时记录每个视口和相机的宽度、高度、相机位置和其他属性。这可以帮助您了解幕后发生的事情。

处理多个视口的示例代码片段

以下是如何设置两个视口并正确渲染它们的示例:

public class MyScreen implements Screen {
    private Stage stage1;
    private Stage stage2;
    private FitViewport viewport1;
    private ScreenViewport viewport2;

    public MyScreen() {
        viewport1 = new FitViewport(800, 600); // Fixed aspect ratio
        viewport2 = new ScreenViewport(); // Stretches to screen

        stage1 = new Stage(viewport1);
        stage2 = new Stage(viewport2);
    }

    @Override
    public void render(float delta) {
        // Clear the screen
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        // Update and draw first stage
        stage1.act(delta);
        stage1.draw();

        // Update and draw second stage
        stage2.act(delta);
        stage2.draw();
    }

    @Override
    public void resize(int width, int height) {
        viewport1.update(width, height, true); // Keep aspect ratio
        viewport2.update(width, height, false); // Stretch to fill screen
    }

    // Other required methods...
}

结论

如果遵循这些准则,您应该可以更好地控制 libGDX 中多个视口的行为。如果您提供有关您遇到的“不可预测”行为的更多细节,我可以提供更有针对性的建议。 apne 电视加拿大。

© www.soinside.com 2019 - 2024. All rights reserved.