AndEngine for Android Game Development Cookbook
上QQ阅读APP看书,第一时间看更新

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.

  1. 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;
  2. Provide load methods that will handle loading the audio, graphical, and font resources declared in the ResourceManager 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);
    }
    }
  3. 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.