Libgdx 按下后退按钮打开应用程序时,纹理很奇怪?

Libgdx textures are all weird when opening app after the back button is pressed?

这就是我的困境,我真的快要在 Play 商店上发布我的游戏了。

在设备上测试我的应用程序时,我发现当 主页按钮 被点击,然后再次打开应用程序时。一切都处理得很好。

但是,当按下 后退按钮 并再次打开该应用程序时,我的游戏中的纹理加载很奇怪,真的很奇怪。

以下是应该看起来像什么不应该看起来像的屏幕截图。

这里是 link 显示应该是什么样子的 http://imgur.com/20QS2bx,bGyhbDJ#0

这是按下后退按钮后加载的那个 http://imgur.com/20QS2bx,bGyhbDJ#1

经过一段时间的测试后,我认为问题在于当单击后退按钮时,它会触发一个 "quit" 类型的函数,该函数应该 EXIT 应用程序。但是,由于某种原因,该应用程序仍然存在于 phone 的背景中,这导致在单击后退按钮后加载了奇怪的纹理。如果我是正确的,我需要做些什么来处理这种行为。

public class MainMenuScreen implements Screen{
    private static final int FLOOR_Y_OFFSET = -150;
    private static final int FOREGROUND_Y_OFFSET = -150;

    private FishyDash game;
    private OrthographicCamera cam;

    private Texture background;
    private Texture foreground;
    private Vector2 foregroundPos1, foregroundPos2;
    private Texture floor;
    private Vector2 floorPos1, floorPos2;
    private Fish fishy;

    //TABLE STUFF
    private Table table;
    private Table buttonTable;
    private Stage stage;

    private Image game_title;
    private Skin skin;
    private TextureAtlas buttonAtlas;
    private TextButton buttonPlay, buttonRate;
    private Viewport gamePort;

    public BitmapFont font;

    //Load all the sounds needed
    public Sound jumpSound;
    public Sound buttonClicked;
    public Music backgroundMusic;

    GameState gameState;

    //On Pause stuff
    public static Vector2 fish_pause_pos;

    public MainMenuScreen(FishyDash game) {
        this.game = game;
        gameState = GameState.READY;

        System.out.println("first");
    }


    @Override
    public void show() {
        System.out.println("second");
        //Initialize all the sounds
        jumpSound = Assets.manager.get(Assets.jumpSound, Sound.class);
        buttonClicked = Assets.manager.get(Assets.buttonClicked, Sound.class);
        backgroundMusic = Assets.manager.get(Assets.backgroundMusic, Music.class);
        backgroundMusic.setLooping(true);
        backgroundMusic.setVolume(.5f);
        backgroundMusic.play();

        //Initialize the textures needed in the MainMenuScreen class
        background = Assets.manager.get(Assets.background, Texture.class);
        floor = Assets.manager.get(Assets.floor, Texture.class);
        foreground = Assets.manager.get(Assets.foreground, Texture.class);

        fishy = new Fish();
        fishy.setPos(80, foreground.getHeight() + FOREGROUND_Y_OFFSET - 150);
        fishy.setMOVEMENT_X(200);
        fishy.setGRAVITY(-40);

        cam = new OrthographicCamera();
        cam.setToOrtho(false, background.getWidth(), background.getHeight());

        foregroundPos1 = new Vector2(cam.position.x - (cam.viewportWidth / 2), 0);
        foregroundPos2 = new Vector2(cam.position.x - (cam.viewportWidth / 2) + foreground.getWidth(), 0);

        floorPos1 = new Vector2(cam.position.x - (cam.viewportWidth / 2), 0);
        floorPos2 = new Vector2(cam.position.x - (cam.viewportWidth / 2) + floor.getWidth(), 0);

        createTable();

//        Gdx.input.setCatchBackKey(true);
//        game.getAdsController().showBannerAd();
    }

    public void createTable() {
        gamePort = new StretchViewport(FishyDash.V_WIDTH, FishyDash.V_HEIGHT, cam);
        stage = new Stage(gamePort, game.batch);
        stage.getViewport().setCamera(cam);

        table = new Table();
        table.setFillParent(true);
        table.setBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

        buttonTable = new Table();
        buttonTable.setFillParent(true);
        buttonTable.setBounds(0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

        game_title = new Image(new Texture("game_title.png"));
        font = Assets.manager.get(Assets.font, BitmapFont.class);
        buttonAtlas = Assets.manager.get(Assets.buttonAtlas, TextureAtlas.class);
        skin = new Skin(buttonAtlas);

        //Creating the TextStyle for the playButton
        TextButton.TextButtonStyle playButtonStyle = new TextButton.TextButtonStyle();
        playButtonStyle.up = skin.getDrawable("button_up");
        playButtonStyle.down = skin.getDrawable("button_down");
        playButtonStyle.pressedOffsetX = 1;
        playButtonStyle.pressedOffsetY = -1;
        playButtonStyle.font = font;

        //Creating the TextStyle for the rateButton
        TextButton.TextButtonStyle rateButtonStyle = new TextButton.TextButtonStyle();
        rateButtonStyle.up = skin.getDrawable("button_up");
        rateButtonStyle.down = skin.getDrawable("button_down");
        rateButtonStyle.pressedOffsetX = 1;
        rateButtonStyle.pressedOffsetY = -1;
        rateButtonStyle.font = font;

        //Setting the style and text for the playButton
        buttonPlay = new TextButton("PlAY", playButtonStyle);
        buttonPlay.pad(10);

        //Setting the style and text for the rateButton
        buttonRate = new TextButton("RATE", rateButtonStyle);
        buttonRate.pad(10);

        table.top();
        table.add(game_title).padTop(175).expandX();

        buttonTable.bottom().padBottom(200);
        buttonTable.add(buttonPlay).expandX().padLeft(30);
        buttonTable.add(buttonRate).expandX().padRight(30);

//        table.debug();
        stage.addActor(table);
        stage.addActor(buttonTable);

        buttonPlay.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                buttonClicked.play();
                dispose();
                game.setScreen(new GameScreen(game));
            }
        });

        buttonRate.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                buttonClicked.play();
                System.out.println("Nothing happens Yet");
            }
        });
    }

    public void updateWorld(float delta) {

        switch (gameState) {
            case READY:

                fishy.update(delta);

                if (fishy.getPosition().y < foreground.getHeight() + FOREGROUND_Y_OFFSET - 35) {
                    fishy.setMOVEMENT_X(100);
                }

                if (fishy.getPosition().y < floor.getHeight() + FLOOR_Y_OFFSET + 150) {
                    fishy.setMOVEMENT_X(100);
                    fishy.normalJump();
                    jumpSound.stop();
                }

                updateForeground();
                updateFloor();

                cam.position.x = fishy.getPosition().x + (cam.viewportWidth / 2) - 80;
                cam.update();

                table.setPosition(cam.position.x - cam.viewportWidth / 2, 0);
                buttonTable.setPosition(cam.position.x - cam.viewportWidth / 2, 0);

                Gdx.input.setInputProcessor(stage);
                break;

            case PAUSED:
                gameState = GameState.READY;
                break;
        }
    }

    public void drawWorld() {
        game.batch.setProjectionMatrix(cam.combined);
        switch (gameState) {

            case READY:
                game.batch.begin();

                game.batch.draw(background, cam.position.x - cam.viewportWidth / 2, 0);

                game.batch.draw(foreground, foregroundPos1.x, foregroundPos1.y + FOREGROUND_Y_OFFSET);
                game.batch.draw(foreground, foregroundPos2.x, foregroundPos2.y + FOREGROUND_Y_OFFSET);

                game.batch.draw(floor, floorPos1.x, floorPos1.y + FLOOR_Y_OFFSET);
                game.batch.draw(floor, floorPos2.x, floorPos2.y + FLOOR_Y_OFFSET);

                game.batch.draw(fishy.getAnimation().getKeyFrame(fishy.timePassed, true),
                        fishy.getPosition().x, fishy.getPosition().y);

                game.batch.end();

                stage.act();
                stage.draw();
                break;

            case PAUSED:
                break;
        }
    }

    @Override
    public void render(float delta) {
        Gdx.gl.glClearColor(1, 1, 1, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        updateWorld(delta);
        drawWorld();
    }

    @Override
    public void dispose() {
        System.out.println("Main Menu Dispose Called");

        fishy.dispose();
        stage.dispose();
    }

    public void updateForeground() {
        if(cam.position.x - (cam.viewportWidth / 2) > foregroundPos1.x + foreground.getWidth())
            foregroundPos1.add(foreground.getWidth() * 2, 0);
        if(cam.position.x - (cam.viewportWidth / 2) > foregroundPos2.x + foreground.getWidth())
            foregroundPos2.add(foreground.getWidth() * 2, 0);
    }

    public void updateFloor() {
        if(cam.position.x - (cam.viewportWidth / 2) > floorPos1.x + floor.getWidth())
            floorPos1.add(floor.getWidth() * 2, 0);
        if(cam.position.x - (cam.viewportWidth / 2) > floorPos2.x + floor.getWidth())
            floorPos2.add(floor.getWidth() * 2, 0);
    }

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

    @Override
    public void pause() {
        System.out.println("pause");
        gameState = GameState.PAUSED;
    }

    @Override
    public void resume() {
        System.out.println("resume");
    }

    @Override
    public void hide() {
        System.out.println("hide");
    }

    public enum GameState {
        READY, PAUSED;
    }
}

编辑:

根据我的理解,将资产管理器更改为下面的内容应该可行,但是当我进行此更改时,我无法再使用管理器,它以红色突出显示并给我错误非静态字段管理器不能从非静态内容中引用?

AssetManager manager = new AssetManager();

    public static final String font = "fonts/mario.fnt";

    public static final String jumpSound = "sounds/jumpSound.wav";
    public static final String buttonClicked = "sounds/buttonClicked.wav";
    public static final String passSound = "sounds/passSound.wav";
    public static final String gameOver = "sounds/gameOver.mp3";
    public static final String backgroundMusic = "sounds/backgroundMusic.wav";

    public static final String background = "background.png";
    public static final String floor = "floor.png";
    public static final String foreground = "foreground.png";

    public static final String fishAtlas = "sprite_animations/fishy_sprite_ani.atlas";
    public static final String buttonAtlas = "ui/buttons.atlas";


    public Assets() {
    }

    public static void load() {
        manager.load(font, BitmapFont.class);

        manager.load(jumpSound, Sound.class);
        manager.load(buttonClicked, Sound.class);
        manager.load(passSound, Music.class);
        manager.load(gameOver, Music.class);
        manager.load(backgroundMusic, Music.class);

        manager.load(background, Texture.class);
        manager.load(floor, Texture.class);
        manager.load(foreground, Texture.class);

        manager.load(fishAtlas, TextureAtlas.class);
        manager.load(buttonAtlas, TextureAtlas.class);

    }

即使您关闭应用程序,存在于后台的对象的静态实例也是有问题的。

确保在应用程序打开资产管理器的所有实例时将其处置、清空和创建为新的。

使用

AssetManager manager;

...

manager.clear();

处理 皮肤,如果你使用一些皮肤并设置 null 到你的处理程序,如果你使用一些作为单例

您应该避免静态资产引用。当 Android Activity 退出时,应用程序会保持活动状态,因此静态引用的对象也会保持活动状态,直到您下次启动游戏(一个新的 Activity 实例)启动器。

从技术上讲,您可以对资产进行静态引用,但如果这样做,您需要确切地知道自己在做什么,而且很容易出错。 (您必须绝对确保 Activity 关闭时所有内容都已处理,清除对 null 的静态引用,并确保在游戏再次启动时加载新实例。)最安全的做法是避免任何对实现 Disposable 的任何内容的静态引用。

您需要阅读 Java 的 class 对象(不是 classes,不是对象,而是 "class objects"),这样您就会明白发生了什么在这。 static 方法不能对非 static 成员变量进行操作,因此您还需要从 load 方法中删除 static 关键字。

然后要访问您的资产管理器,您需要创建资产实例 class 并通过标准成员变量访问它:

public class FishyDash extends Game {

    Assets assets;

    public void create(){
        assets = new Assets();
        assets.load();
        //....
    }

}

public class MainMenuScreen implements Screen{

    //...

    public void show() {
        System.out.println("second");

        jumpSound = game.assets.manager.get(Assets.jumpSound, Sound.class);
        //...
    }

    //...

}

这是更危险的答案。我只建议您在完全理解 Android 生命周期、Libgdx 生命周期和 Java 的 class 对象的情况下执行此操作。

您可以保留您的静态资产引用,但您必须确保它们在游戏结束时被处理掉。

public class Assets {

    //Safer to keep this private and use below public method for access
    private static AssetManager manager; //do not instantiate here

    public static AssetManager manager(){
        if (manager == null) load();
        return manager;
    }

    public static void load (){
        if (manager == null) manager = new AssetManager();

        //your existing load code
    }

    public static void dispose() {
        if (manager != null){
            manager.dispose();
            manager = null;
       }
    }

}

public class FishyDash extends Game {

    //...

    @Override
    public void dispose() {
        Assets.dispose();
    }
}

public class MainMenuScreen implements Screen{

    //...

    public void show() {
        System.out.println("second");

        //NOTE THE PARENTHESES AFTER manager below
        jumpSound = Assets.manager().get(Assets.jumpSound, Sound.class);
        //...
    }

    //...

}