libgdx/Android:应用程序销毁/暂停后图形消失

5
我正在进行一些测试,发现在我的Nexus 5上,当我按下返回键(或主页键) - 也就是说,当上下文发生改变时 - 并且我回到游戏时,openGL上下文会丢失。
没有纹理了(它们显示为黑色),UI的皮肤也没有了(按钮是白色的)。
我以为这会被libgdx自动管理,对吧?那么为什么会发生这种情况?
我通过TextureAtlas创建纹理,像这样:
TextureAtlas atlas;
TextureRegion bg;
atlas = new TextureAtlas(Gdx.files.internal("mainMenu.atlas"));
bg = atlas.findRegion("bg");

然后它与batch.draw(bg, x, y, w, h);一起使用。

我还尝试着创建一个TextureRegion,直接加载一个纹理而不是TextureAtlas(只是为了确认这问题是否出在TextureAtlas),但我得到的结果还是一样的......

有人能解决吗?

编辑:更具体的代码:

屏幕类基础:

public class MainMenuScreen extends ScreenManager.Screen {

        private Game game;
    private InputMultiplexer inputMultiplexer = new InputMultiplexer();

    private MainMenuUi screenUi;
    private MainMenuView screenView;

    private TextureAtlas atlas;

    public MainMenuScreen(ConbiniGame game) {
        this.game = game;

        atlas = new TextureAtlas(Gdx.files.internal("mainMenu.atlas"));
        screenUi = new MainMenuUi(game);
        screenView = new MainMenuView(atlas);

        inputMultiplexer.addProcessor(screenUi.getInputProcessor());
        inputMultiplexer.addProcessor(screenView.getInputProcessor());

        Gdx.input.setInputProcessor(inputMultiplexer);
    }

    // ...
}

在MainMenuView类中,使用了TextureAtlas...

public class MainMenuView {

    private Stage stage;
    private OrthographicCamera camera;
    private Viewport viewport;

    private TextureAtlas atlas;
    TextureRegion bg;

    public MainMenuView(TextureAtlas atlas) {
        atlas = atlas;
        bg = atlas.findRegion("bg");

        camera = new OrthographicCamera();
        camera.setToOrtho(false);
        viewport = new FitViewport(1080, 1920, camera);
        stage = new Stage(viewport);
    }

    public void update(float delta) {
        stage.act(delta);
    }

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

        stage.getBatch().begin();
        stage.getBatch().draw(bg, 0, 0, stage.getCamera().viewportWidth, stage.getCamera().viewportHeight);
        stage.getBatch().end();

        stage.draw();
    }

    public InputProcessor getInputProcessor() {
        return stage;
    }
}

代码只是展示纹理的使用,其他部分已被移除。
3个回答

4
你没有提供足够的信息,但你的问题很可能是由于在代码中使用了 "static"。不要这样做。
当你按下返回按钮时,你的应用程序会关闭。当你按下主页按钮时,你的应用程序会暂停。请注意,这是两件不同的事情。因此,当使用主页按钮时,你可能不总是遇到问题。这是因为当你的应用程序暂停时,android 可能决定关闭它(以释放内存),但并不保证这样做。
无论哪种方式,这都与 opengl 上下文丢失无关。它只是关闭了。如果上下文确实丢失了,那么 libgdx(以及 android 的后续版本)将为你恢复它。
当你关闭应用程序然后立即重新启动它时,Android 可能会重用相同的 VM 用于该应用程序的实例。这也意味着任何静态变量都将具有前一个应用程序运行时它们所具有的值。如果其中任何变量包括(可能是间接的)任何资源,则这些资源将不再有效。
tl;dr 不要在 Android 应用程序中使用 static。
最常见的错误(在没有看到你的代码的情况下,这只是猜测)是通过使用单例来访问资源。例如:MyGame.getInstance().assets.get("atlas",...); 不要这样做,因为由于上述原因,它将失败。相反,将你的 MyGame 实例的引用传递给需要它的任何类(例如你的 Screen: new MenuScreen(this);)。

我明白了。之前不知道在Android中关于静态变量的问题。我刚开始学 ;) 我现在会尝试不使用静态变量,但是如果我理解正确的话,你建议将所有的资源管理器作为主游戏类的实例变量存储,是吗?谢谢。 - danikaze
1
那只是一个例子。如果在你的游戏中将资产成员作为一部分能够工作,那就使用它;如果你更喜欢其他东西,那就使用其他东西。但不要使用静态变量。顺便说一句,你永远不应该有多个AssetManager实例。 - Xoppa
1
我尝试移除了单例、静态等,现在纹理被加载到屏幕的实例变量中...但问题仍然存在...还有其他想法吗? - danikaze
正在更新问题,附带更具体的代码 ;) - danikaze
1
resume 方法中,您不需要重新加载资源。更重要的是,仅调用 AssetManager#finishLoading()resume 方法中将没有任何效果,该调用不会重新加载任何内容。LibGDX 会根据需要为您重新加载它们。但是,当 libGDX 这样做时,您可以显示一个加载屏幕。在这种情况下,您需要调用 Texture.setAssetManager,然后自己处理更新,请参见:https://github.com/libgdx/libgdx/wiki/Managing-your-assets#resuming-with-a-loading-screen - Xoppa
显示剩余4条评论

0

当我做第一个 LibGDX 游戏 - Flappy Bird 克隆时,我遇到了同样的问题。结果问题并不在于纹理,而是与我用于速度的 MEMBER Vector2/Vector3 变量有关。

为了使小鸟从指定高度落下,我声明了以下内容: 1. 一个成员 int 变量表示重力(初始化为 -15), 2. 一个 Vector2 成员变量表示小鸟位置,初始化为 (50, 300),以及 3. 另一个 Vector2 成员变量表示速度,初始化为 0,0

现在,在 update() 方法中,我通过 velocity.add(0, gravity) 将重力作为值传递给速度的 y 轴参数。

然后我使用 velocity.scl(dt) 进行缩放。 接着将该速度添加到位置上,并再次取消缩放,使用 velocity.scl(1/dt)。 最后一行是导致错误的原因,但由于它对我的游戏功能至关重要,所以我不能删除它。 我的解决方案是将速度变量从成员变量更改为局部变量,这样在游戏暂停时,纹理就不会消失了。


0

实际上,对于纹理管理,使用Singleton或其他静态模式是可以的。你需要做的唯一一件事就是使静态内容依赖于游戏实体,以避免黑色矩形问题:

private static TextureStore sStore = null;
private static MyGdxGame sGame;

static public TextureStore getStore()
{
    if(sStore==null||sGame!=MyGdxGame.getGame())
    {
        sStore = new TextureStore();
        sGame = MyGdxGame.getGame();
    }
    
    return sStore;
}

在游戏实体中

@Override
public void create()
{
    sGame = this;
...

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接