【问题标题】:Libgdx textures are all weird when opening app after the back button is pressed?按下后退按钮后打开应用程序时,Libgdx 纹理都很奇怪?
【发布时间】:2015-09-10 21:51:47
【问题描述】:

所以这是我的困境,我真的很接近在 Play 商店上发布我的游戏了。

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

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

以下是应该是什么样子和不应该是什么样子的屏幕截图。

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

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

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

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 或纹理进行静态引用。退出 Android Activity 并不会退出整个应用程序,因此静态引用会保留。
  • @Tenfour04 我添加了我的资产代码,我希望你能就此启发我。我在 wiki 中读到这是做事的正确方法,但我似乎无法使用 manager.load()?
  • 你能链接到维基上说要这样做的地方吗?从技术上讲,您可以对资产进行静态引用,但如果这样做,您需要确切地知道自己在做什么,而且很容易出错。初学者经常犯这个错误,所以应该清理维基。
  • link 我仍在尝试解决这个问题,但我不确定该怎么做。所以现在在我的资产类的处置方法中,我在处置经理之后添加了 manager = null。我尝试使用 Gdx.input.setCatchBackKey(true) 然后在其中处理 assest 但它只会加载黑屏
  • 该链接显示:注意并继续告诉您为什么您不应该在资产中使用static关键字。

标签: android libgdx scene2d


【解决方案1】:

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

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

您需要阅读 Java 的类对象(不是类,不是对象,而是“类对象”),以便了解这里发生了什么。 static 方法不能对非static 成员变量进行操作,因此您还需要从load 方法中删除static 关键字。

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

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

    //...

}

【讨论】:

  • 天哪!我现在非常爱你,这绝对是我需要的那种信息,抱歉我不太了解你以前的 cmets.. 但是我知道我的错误,我完全忽略了我的加载方法是静态的我不知道如何但我做过。我只是没有把两个和两个放在一起。但这就是解决方案!非常感谢!
【解决方案2】:

即使您关闭应用程序,背景中存在对象的静态实例也会出现问题。

确保当应用打开资产管理器的所有实例时,您正在处置、清空和创建新的。

使用

AssetManager manager;

...

manager.clear();

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

【讨论】:

  • 我不相信我使用任何静态实例变量?
  • 然后检查您的资产管理器或您应该处置的其他对象 - 列表在这里:github.com/libgdx/libgdx/wiki/Memory-management
  • 好的,所以我使用了这个公共静态最终 AssetManager manager = new AssetManager();但现在我把它改成了这个 AssetManager manager = new AssetManager();但是问题是它给了我错误 non static field 'manager' cannot be referenced from a static context。我的马槽现在是红色的,有什么解决办法吗?
  • 您不需要将 static 字段设为非静态!如果您将它用作静态保留它 - 只需确保在 dispose 方法上您正在处理它并将引用设置为 null - 仅此而已
【解决方案3】:

这是更危险的答案。如果您完全了解 Android 生命周期、Libgdx 生命周期和 Java 的类对象,我只建议您这样做。

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

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

    //...

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-02
    • 1970-01-01
    • 2016-08-31
    • 1970-01-01
    • 1970-01-01
    • 2020-04-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多