LibGDX FitViewport 可以正确调整大小,但在更换屏幕后会重置

LibGDX FitViewport resizes properly, but resets after changing screens

我在 LibGDX 中遇到 FitViewport 的问题。调整 window 大小时,一切正常。接下来我切换屏幕,一切都回到正常尺寸,图像被裁剪到左侧,而应用程序的尺寸保持调整大小。

调整大小后,FitViewport 工作正常:

但是,当我按下 to first screen 按钮时,会发生这种情况:

所以一切正常(按 to main screen 按钮将带您回到原始屏幕),除了按钮和图像的缩放和定位。

window 的尺寸保持不变,但图像恢复为原始大小(即 500x500)并放置在坐标 (0,0) 处。

关于如何解决这个问题有什么想法或建议吗?我正在为这个问题而烦恼,似乎无法正确处理...我希望它就像第一个屏幕一样。


这些是我的 class 文件:我使用抽象屏幕 class 来跟踪屏幕(以及稍后扩展)和屏幕管理器:

主要class:

public class MainClass implements ApplicationListener {

    @Override
    public void create () {
        ScreenManager.setScreen(new MainScreen());
    }

    @Override
    public void render () {
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        if (ScreenManager.getCurrentScreen() != null) {
            ScreenManager.getCurrentScreen().render();
        }
    }

    @Override
    public void resize(int width, int height) {
        if (ScreenManager.getCurrentScreen() != null)
            ScreenManager.getCurrentScreen().resize(width, height);
    }
}

摘要屏幕Class:

public abstract class Screen {

    public abstract void create();

    public abstract void render();

    public abstract void resize(int width, int height);

    public abstract void pause();

    public abstract void dispose();

    public abstract void resume();
}

屏幕管理器Class:

public class ScreenManager {

    private static Screen currentScreen;

    public static void setScreen(Screen screen) {
            if (currentScreen != null)
            currentScreen.dispose();
        currentScreen = screen;
        currentScreen.create();
    }

    public static Screen getCurrentScreen() {
        return currentScreen;
    }
}

主屏幕Class:

public class MainScreen extends Screen {

    private Texture bg1;
    private Image bg1Image;
    private Skin skin;

    private Stage stage;
    private OrthographicCamera camera;
    private FitViewport fitViewport;

    @Override
    public void create() {
        camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        fitViewport = new FitViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), camera);

        bg1 = new Texture(Gdx.files.internal("background1.png"));
        bg1Image = new Image(bg1);
        skin = new Skin(Gdx.files.internal("uiskin.json"));

        TextButton nextButton = new TextButton("to first screen", skin);
        nextButton.setPosition(200, 200);
        nextButton.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                ScreenManager.setScreen(new FirstScreen());
                super.clicked(event, x, y);
            }
        });

        stage = new Stage(fitViewport);
        stage.addActor(bg1Image);
        stage.addActor(nextButton);

        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void render() {
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        stage.act(Gdx.graphics.getDeltaTime());

        fitViewport.apply();
        stage.draw();
    }

    @Override
    public void resize(int width, int height) {
        fitViewport.update(width, height, true);
        camera.update();
    }
}

第一屏Class:

public class FirstScreen extends Screen {

    private Texture bg2;
    private Image bg2Image;
    private Skin skin;

    private Stage stage;
    private OrthographicCamera camera;
    private FitViewport fitViewport;

    @Override
    public void create() {
        camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        fitViewport = new FitViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), camera);

        bg2 = new Texture(Gdx.files.internal("background2.png"));
        bg2Image = new Image(bg2);
        skin = new Skin(Gdx.files.internal("uiskin.json"));

        TextButton prevButton = new TextButton("to main screen", skin);
        prevButton.setPosition(200, 200);
        prevButton.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                ScreenManager.setScreen(new MainScreen());
                super.clicked(event, x, y);
            }
        });

        stage = new Stage(fitViewport);
        stage.addActor(bg2Image);
        stage.addActor(prevButton);

        Gdx.input.setInputProcessor(stage);
    }

    @Override
    public void render() {
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        stage.act(Gdx.graphics.getDeltaTime());

        fitViewport.apply();
        stage.draw();
    }

    @Override
    public void resize(int width, int height) {
        fitViewport.update(width, height, true);
        camera.update();
    }
}

(我知道我提供了很多classes,但我想详细解释一切......) 我猜这可能是一些小事,但我似乎做对了,这让我发疯了…… 任何帮助或建议将不胜感激!

当您使用 ScreenManager 创建新屏幕时,您不会在新实例化的屏幕上调用 resize。它是第一次工作,因为您是在 ApplicationListener 上调用 resize 之前创建第一个屏幕,而 ApplicationListener 又会在屏幕上调用 resize

顺便说一句,您还必须在这些屏幕超出范围之前调用 dispose,否则会泄漏内存。 dispose 屏幕的 dispose 方法中的所有资产、批次等(任何实现 Disposable 的东西)。

你的问题在这里:

    camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    fitViewport = new FitViewport(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), camera);

每次检查当前 window 大小并创建 window 具有的大小的视口。解决方案是手动定义 window 大小并根据此值创建新的屏幕视口。

在您的 Main class 中创建静态 public 大小变量(您当然可以在您想要或不创建但直接写入值的任何地方创建它 -但由于未来的重构,这并不好)

    public static final float WIDTH = 800, HEIGHT = 600; //or any other values you need

然后像

一样创建视口和相机
    camera = new OrthographicCamera(Main.WIDTH, Main.HEIGHT);
    camera.setToOrtho(false, Main.WIDTH, Main.HEIGHT);
    fitViewport = new FitViewport(Main.WIDTH, Main.HEIGHT, camera);

就这些了。


如果您不需要这个,也请考虑不要创建新相机 - 也许默认的 stage 相机对您来说足够了?想想看。