Creating the resource manager
In this topic, we're finally going to look at our resources from a bigger picture. With the resource manager in place, we will easily be able to make a single call to methods such as loadTextures()
, loadSounds()
, or loadFonts()
in order to load the different types of resources needed by our game, all from a single, convenient location.
Getting ready
Please refer to the class named ResourceManager
in the code bundle.
How to do it…
The ResourceManager
class is designed with the singleton design pattern in mind. This allows for global access to all of our game's resources through a simple call to ResourceManager.getInstance()
. The main purpose of the ResourceManager
class is to store resource objects, load resources, and unload resources. The following steps display how we can use ResourceManager
to handle textures of one of our game's scenes.
Declare all of the resources that will be used throughout the different scenes in our game:
/* The variables listed should be kept public, allowing us easy access to them when creating new Sprites, Text objects and to play sound files */ public ITextureRegion mGameBackgroundTextureRegion; public ITextureRegion mMenuBackgroundTextureRegion; public Sound mSound; public Font mFont;
Provide
load
methods that will handle loading the audio, graphical, and font resources declared in theResourceManager
class:public synchronized void loadGameTextures(Engine pEngine, Context pContext){ // Set our game assets folder in "assets/gfx/game/" BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/game/"); BuildableBitmapTextureAtlas mBitmapTextureAtlas = new BuildableBitmapTextureAtlas(pEngine.getTextureManager(), 800, 480); mGameBackgroundTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mBitmapTextureAtlas, pContext, "game_background.png"); try { mBitmapTextureAtlas.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(0, 1, 1)); mBitmapTextureAtlas.load(); } catch (TextureAtlasBuilderException e) { Debug.e(e); } }
The third step involves providing a method of unloading all resources corresponding to our
ResourceManager
class'load
methods:public synchronized void unloadGameTextures(){ // call unload to remove the corresponding texture atlas from memory BuildableBitmapTextureAtlas mBitmapTextureAtlas = (BuildableBitmapTextureAtlas) mGameBackgroundTextureRegion.getTexture(); mBitmapTextureAtlas.unload(); // ... Continue to unload all textures related to the 'Game' scene // Once all textures have been unloaded, attempt to invoke the Garbage Collector System.gc(); }
How it works…
By implementing a ResourceManager
class into our project, we can easily load our various scene resources completely indepenently of one another. Because of this, we must make sure that our public
class methods are synchronized in order to make sure that we're running in a thread-safe environment. This is especially important with the use of singletons, as we've only got one instance of the class, with the potential for multiple threads accessing it. On top of that, we now only require one line of code when it comes to loading our scene resources which helps greatly in keeping our main activity class more organized. Here is what our onCreateResources()
methods should look like with the use of a resource manager:
@Override public void onCreateResources( OnCreateResourcesCallback pOnCreateResourcesCallback) { // Load the game texture resources ResourceManager.getInstance().loadGameTextures(mEngine, this); // Load the font resources ResourceManager.getInstance().loadFonts(mEngine); // Load the sound resources ResourceManager.getInstance().loadSounds(mEngine, this); pOnCreateResourcesCallback.onCreateResourcesFinished(); }
In the first step, we are declaring all of our resources, including Font
objects, ITextureRegion
objects, and Sound
/Music
objects. In this particular recipe, we're only working with a limited number of resources, but in a fully-functional game, this class may include 50, 75, or even more than 100 resources. In order to obtain a resource from our ResourceManager
class, we can simply include the following line into any class within our project:
ResourceManager.getInstance().mGameBackgroundTextureRegion
.
In the second step, we create the
loadGameTextures(pEngine, pContext)
method which is used to load the Game
scene textures. For every additional scene within our game, we should have a separate load
method in place. This allows for easy loading of resources on the fly.
In the final step, we're creating unload
methods which handle unloading the resources corresponding to each of the load
methods. However, if there are any number of resources which happen to be used throughout a number of our game's scenes, it might be necessary to create a load
method which doesn't come with an accompanying unload
method.
There's more…
In larger projects, sometimes we may find ourselves passing main objects to classes very frequently. Another use for the resource manager is to store some of the more important game objects such as the Engine
or Camera
. This way we no longer have to continuously pass these objects as parameters, rather we can call respective get
methods in order to get the game's Camera
, Engine
, or any other specific object we'll need to reference throughout the classes.
See also
Introducing sounds and music in this chapter.
Working with different types of textures in this chapter.
Using AndEngine font resources in this chapter.