AssetManager Custom Loaders

When I was first learning libgdx I thought to myself, “Self, you should never load an asset from disk more than once if you don’t have to.” So I began writing several different classes to manage loading and retrieving each type of object. Now I have found that Libgdx has done the work for me – more elegantly than I was doing myself – with the AssetManager.

For any of my fellow libgdx newbs out there, the AssetManager contains a handful of really handy loader classes so that you can hand the AssetManager a path and a class type and it will not only load the asset for you, but employ reference counting to ensure that the asset is only loaded once and that it is disposed of after no one is using it anymore.

So great was the AssetManager’s power, that I decided that I wanted to write my own loader classes for some custom assets. Along the way, I found the documentation a little hard to understand, so here’s a short tutorial on writing a custom asset loader.

For my custom asset, I have XML files which define several animation states that an actor can be in which I have given the .animation extension. I wanted to write a custom loader to load these animations. The class that represents these animations once in memory is called AnimationCollection.

So lets start off by creating our class declarations. We need both a class for our custom loader as well as an inner class that can be used to pass any parameters we want to our loader. However, right now the parameters class does not contain any data, but could easily be modified to contain options for loading the asset.

public class AnimationCollectionLoader extends SynchronousAssetLoader<AnimationCollection, AnimationCollectionLoader.AnimationCollectionParameters> {
     static public class AnimationCollectionParameters extends AssetLoaderParameters<AnimationCollection> {}
}

SynchronousAssetLoader has two abstract methods that we need to implement. Plus we need to implement a constructor which passes the file resolver to the parent.

public AnimationCollectionLoader (FileHandleResolver resolver) {
     super(resolver);
}

@Override
public Array<AssetDescriptor> getDependencies (String fileName, FileHandle animationFile, AnimationCollectionParameters parameter) {
     Array<AssetDescriptor> dependencies = new Array();
     return dependencies;
}

@Override
public AnimationCollection load(AssetManager manager, String fileName, FileHandle file, AnimationCollectionParameters parameter) {
     AnimationCollection collection = new AnimationCollection();
     return collection;
}

The load method is pretty straightforward, you just create and initialize an AnimationCollection and then return it. However, the getDependencies() method tripped me up for a while. The purpose of getDependencies is to tell the AssetManager what other assets need to be loaded before your asset is loaded. It is not, as I originally thought, the place where you actually grab these dependencies. Every asset that is mentioned in the return array from getDependencies will be loaded and available to you during the load() method. There are several flavors of AssetDescriptor’s constructor, but each one lets you tell the asset manager that you depend on a file loaded into a specific class type.

Now for an example. My AnimationCollection depends on a TextureAtlas which is mentioned in the very first XML tag of the .animation file. I need to report this dependency in getDependencies(). Here is how my methods looked to accomplish that (with a little exception handling code omitted).

String atlasFileName;
@Override
public Array<AssetDescriptor> getDependencies (String fileName, FileHandle animationFile, AnimationCollectionParameters parameter) {
     Array<AssetDescriptor> dependencies = new Array();
     FileHandle animationParent = animationFile.parent();
     XmlReader xmlReader = new XmlReader();
     Element animationElement = xmlReader.parse(animationFile);
     String atlasName = animationElement.getAttribute("atlas");
     FileHandle atlasPath = animationParent.child(atlasName);
     AssetDescriptor atlasDependency = new AssetDescriptor(atlasPath,TextureAtlas.class);
     atlasFileName = atlasPath.path();
     dependencies.add(atlasDependency);
     
     return dependencies;
}

@Override
public AnimationCollection load(AssetManager manager, String fileName, FileHandle file, AnimationCollectionParameters parameter) {
     AnimationCollection collection = new AnimationCollection();
     TextureAtlas animationAtlas = manager.get(atlasFileName,TextureAtlas.class);
     collection.setAtlas(animationAtlas);
     collection.load(file);
     return collection;
}

And lastly, the way that you use this custom loader

AssetManager assetManager = new AssetManger();
assetManager.setLoader(AnimationCollection.class,new AnimationCollectionLoader());

//Then, when you want to load the asset
assetManager.load("myanimation.animation",AnimationCollection.class);

//And retrieving the asset later
AnimationCollection collection = assetManager.get("myanimation.animation",AnimationController.class);

One thought on “AssetManager Custom Loaders

Leave a Reply

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

Solve this equation to verify you are a not a computer * Time limit is exhausted. Please reload the CAPTCHA.