【问题标题】:LibGDX FitViewport resizes properly, but resets after changing screensLibGDX FitViewport 正确调整大小,但在更改屏幕后重置
【发布时间】:2015-09-12 03:38:44
【问题描述】:

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

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

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

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

窗口的尺寸保持不变,但图像恢复到其原始尺寸(即 500x500)并放置在坐标 (0,0)。

关于如何解决这个问题的任何想法或建议?我正在为这个问题头疼,似乎无法正确处理...我希望它就像第一个屏幕一样。


这些是我的类文件:我使用一个抽象的 Screen 类来跟踪屏幕(以及以后扩展)和一个 ScreenManager:

主类:

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);
    }
}

抽象屏幕类:

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();
}

屏幕管理类:

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;
    }
}

主屏幕类:

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();
    }
}

第一个屏幕类:

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();
    }
}

(我知道我提供了很多课程,但我想详细解释一切......) 我猜这可能是小事,但我似乎无法正确处理它,这让我发疯了...... 任何帮助或建议将不胜感激!

【问题讨论】:

    标签: java libgdx viewport window-resize


    【解决方案1】:

    你的问题在这里:

        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);
    

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

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

        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 相机对您来说就足够了吗?想一想。

    【讨论】:

    • 谢谢,成功了 :) 你是对的,我在视口中添加了错误的窗口大小。现在你说的似乎很明显。感谢您的相机提示,我实际上并不需要它。当我只使用默认相机时会容易得多。
    【解决方案2】:

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

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

    【讨论】:

    • 我尝试在create方法中调用resize方法,但没有任何效果。我必须在屏幕上的哪个位置拨打resize?我尝试了不同的事情,但没有成功。此外,关于dispose,每次设置新屏幕时,都会在前一个屏幕上调用dispose 方法,然后依次处理所有内容。我只是没有将dispose 方法添加到我的示例中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-02
    • 1970-01-01
    • 2015-09-08
    • 1970-01-01
    • 2019-02-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多