Asset Loading in LibGDX

If you are reading this, you probably already know what LibGDX is. Maybe you found this article in a Google search for asset loading and you are hoping to find some useful information.

So here I am telling you how we at BeeMelonStudio did it!

Disclaimer: This is just our way, we think it is the most convenient, to easily load our assets. For big games with many sprites you maybe be better of with different ways. For example a text file that holds your asset paths or even a SQLite database.

Let’s get started:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
public class Assets {

    private static final AssetManager assetManager = new AssetManager();

    private static HashMap files;

    /**
    * Enter all files from the assets folder in here
    */

    public static void load(){

        files = new HashMap();

        //TextureAtlases
        files.put("backgroundTextureAtlas", new AssetFile("sprites/background.atlas", TextureAtlas.class));
        files.put("entitiesTextureAtlas", new AssetFile("sprites/entities.atlas", TextureAtlas.class));
        files.put("uiTextureAtlas", new AssetFile("sprites/ui.atlas", TextureAtlas.class));

        //Skins
        files.put("defaultSkin", new AssetFile("skins/default/uiskin.json", Skin.class));
        files.put("pixthulhuSkin", new AssetFile("skins/pixthulhu/pixthulhu-ui.json", Skin.class));

        //I18Ns
        files.put("defaultI18N", new AssetFile("i18N/prototype", I18NBundle.class));

        //Loading files
        for(AssetFile asset : files.values()){
            assetManager.load(asset.path, asset.type);
        }

        assetManager.finishLoading();
    }

    public static Object get(String hashmapKey){
        return assetManager.get(files.get(hashmapKey).path, files.get(hashmapKey).type);
    }

    public static void dispose(){
        assetManager.dispose();
    }
}

Let’s look at our class fields first. We have three main things that are important here: Our AssetManager, which is provided to us by LibGDX and handles the more or less complicated stuff for us. Next we have a HashMap that will hold all of our assets. In our case we have a String for the key and our next important thing, the AssetFile, for the value.

1
2
3
private static final AssetManager assetManager = new AssetManager();

private static HashMap files;

Nothing complicated here. Now, let’s look at the AssetFile:

1
2
3
4
5
6
7
8
9
10
public class AssetFile {

    public String path;
    public Class type;

    public AssetFile(String path, Class type) {
        this.path = path;
        this.type = type;
    }
}

As you can see the AssetFile doesn’t really do much, it’s just holding the path and the type of our asset.
Until now it’s pretty straight forward. How about some more action?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static void load(){

    files = new HashMap();

    //TextureAtlases
    files.put("backgroundTextureAtlas", new AssetFile("sprites/background.atlas", TextureAtlas.class));
    files.put("entitiesTextureAtlas", new AssetFile("sprites/entities.atlas", TextureAtlas.class));
    files.put("uiTextureAtlas", new AssetFile("sprites/ui.atlas", TextureAtlas.class));

    //Skins
    files.put("defaultSkin", new AssetFile("skins/default/uiskin.json", Skin.class));
    files.put("pixthulhuSkin", new AssetFile("skins/pixthulhu/pixthulhu-ui.json", Skin.class));

    //I18Ns
    files.put("defaultI18N", new AssetFile("i18N/prototype", I18NBundle.class));

    //Loading files
    for(AssetFile asset : files.values()){
        assetManager.load(asset.path, asset.type);
    }

    assetManager.finishLoading();
    //while(!assetManager.update()){} <- Use this for loading screens.
}

Our load() method is later the first thing called in our game class to assure that everything is loaded before we do any rendering. You can also do it later in your game for example when you want a loading screen. In FourElements we didn’t have the need for one so we skipped it.
Here we are putting our assets into our HashMap. I personally like attaching the object name to the key value. This way makes reading the code easier for others.
It’s important to notice that the path to our actual file is relative to the android/assets directory in our project.
After adding our assets to the HashMap we loop over them and assign them to the asset manager.

1
2
3
4
5
6
7
public static Object get(String hashmapKey){
    return assetManager.get(files.get(hashmapKey).path, files.get(hashmapKey).type);
}

public static void dispose(){
    assetManager.dispose();
}

The last two methods in our Assets class are get(String hashmapKey) and dispose(). If you’re already familiar with LibGDX you know the latter.
Our get(String hashmapKey) method does exactly what its name suggests. It returns the asset we asked for from the asset manager. Here drops in the advantage of our AssetFile class. We can retrieve any assets from the manager by providing only a single string and therefore don’t need to remember any paths or class types.

If you now want to get your assets from any point in your game you can simply do this with one line of code:

1
TextureAtlas textureAtlas = (TextureAtlas) Assets.get("entitiesTextureAtlas");

Conclusion

Loading all files in one place definitely keeps your code clean and making changes is as easy as changing a single line of code.
There is one thing I am not quite happy with. Getting your assets from the Asset class via the get(String hashmapKey) always requires you to cast to the right object. This can be quite annoying if you do this often. This is also another reason why I put the object name into the key value of our HashMap, to remember myself which type I have to cast to.
As you may already noticed this way is not the perfect. As I said earlier for asset heavy games using file formats like XML, json or even plain text can be an even better way. For FourElements this way is enough, but maybe our next project will see some new asset loading methods.
So stay tuned and
be calm, be cool, be(e)melon!

Leave a Reply

Your email address will not be published. Required fields are marked *