Вопрос

I'm working in an Android game using libGDX framework while a learn from their wiki and Learning Libgdx Game Development book. The author of the book defines an Assets class to load game assets using an AssetManager. Every time the game is resumed the assets need to be reloaded so he use a call to Assets.intance.init(new AssetManager()) what reload the assets and create new objects to store textures references.

When I do this in my game, after resume, all I have are black boxes where I had nice textures so I suppose that the problem here is that I'm using the old references. I put here part of the code from the book:

AssetManager#init

public void init(AssetManager assetManager) {

    /* Dispose previous asset manager */
    if (this.assetManager != null) {
        this.assetManager.dispose();
    }

    this.assetManager = assetManager;

    assetManager.setErrorListener(this);
    assetManager.load(Constants.TEXTURE_ATLAS, TextureAtlas.class);

    /* Start loading assets and wait until finished */
    assetManager.finishLoading();

    Array<String> assetNames = assetManager.getAssetNames();
    Gdx.app.debug(TAG, "Assets loaded: " + assetNames.size);
    for (String assetName : assetNames) {
        Gdx.app.debug(TAG, "Asset: " + assetName);
    }

    TextureAtlas atlas = assetManager.get(Constants.TEXTURE_ATLAS);

    /* Create game resource objects. Here I get what I need from the atlas */
    player = new AssetPlayer(atlas);
    enemy = new AssetEnemy(atlas);
}

When I create my game objets I use Assets.instance.player and Assets.instance.enemy to store a reference to textures as the author of the book does so this could be the problem. The thing is that aftere re-read the book, I don't see how he solve this problem.

I'm pretty sure that I can solve the problem changing references in my game objects but all is becoming so messy. My real question is, how should I manage game assets in my game? I've been searching a lot for game examples but most of them don't use an AssetManager but instead static variables to textures.

Should I keep references of textures in game objects? It is really necessary to reload assets on resume? How could I reload textures in my game objects when all the objects are inside a worldController that don't know when a game is being resumed?

Это было полезно?

Решение

You're doing it correctly, as far as I can tell, at this level. You really do need to reload the textures, as your OpenGL context was lost, and all "pointers" into OpenGL-internal state are stale.

As you point out, because your AssetManager.player property points to a new object, anything that cached an old pointer is stale after a restart, and that is probably the source of your problems. (Though its hard to say for certain.)

If you look at the Libgdx SuperJump demo, they also cache all their asset pointers in static fields, but notice that the render calls effectively look up the texture every call. See WorldRenderer.renderBob(). One alternative would be to do a pass over your objects after (re)-loading assets to have them "refresh" their pointers the assets they use.

Другие советы

Have you tried not to call Assets.intance.init(new AssetManager()) on resume method (and also not to call Assets.intance.dispose() on pause method)? Please read this link: https://github.com/libgdx/libgdx/wiki/Managing-your-assets

At the end (Resuming with a Loading Screen) it says:

On Android your app can be paused and resumed. Managed OpenGL resources like Textures need to be reloaded in that case, which can take a bit of time. If you want to display a loading screen on resume, you can do the following after you created your AssetManager.

Texture.setAssetManager(manager);

In your ApplicationListener.resume() method you can then switch to your loading screen and call AssetManager.update() again until everything is back to normal.

If you don't set the AssetManager as shown in the last snippet, the usual managed texture mechanism will kick in, so you don't have to worry about anything.

So, I believe that the author's approach is no longer necessary.

You only need to call Assets.intance.dispose() on dispose method in your "Game" class (I mean, the class that implements ApplicationListener).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top