Resource Management in Game

Introduction

This post is the next in the game development series. In this post we will learn about Resource Management in the Game. After writing the game engine, now we can add some background to our game. We will try to add our menu as well and try to add navigation in the menu. Once that is done we will be able to move through the menu and choose various options. Without wasting much time, lets dive in.

Objects in the Game

There are many different type of entities in our game. They can be categorized into Screens and Actors and few more. You have absolute freedom to make it more granular but this is a good categorization for simplicity. Let us have an Entity interface which defines a contract for all the game objects.
public interface Entity {
    public int getX();
    public int getY();	
    public int getWidth();
    public int getHeight();
    public void tick();
    public void render(Graphics g);
    public Rectangle getBounds();
}
This means that every game entity will have X and Y co-ordinates, width , height, a tick method to update its state, a render method to render this object on the game canvas and a getBounds method which will be used to detect collisions. We can debate on moving getBounds to a lower level in the hierarchy, but it doesn't hurt here as well. Let us implement this interface to get a GameObject class.
public abstract class GameObject implements Entity {
   protected int x;
   protected int y;
   protected int width;
   protected int height;
   public GameObject() {
   }
   public GameObject(int x, int y) {
      this.x = x;
      this.y = y;
   }
   @Override
   public int getX() {
      return this.x;
   }
   @Override
   public int getY() {
      return this.y;
   }
   public int getWidth() {
      return this.width;
   }
   public int getHeight() {
      return this.height;
   }
   public Rectangle getBounds() {
      return new Rectangle(this.x, this.y, this.width, this.height);
   }
}

Resource Management in Game

You can create an image using any photo editing tool, one with some dark sky and few stars will work. Name it background.jpg. We need two things for managing all images in our game.
Loading Images
  • An image loader, which loads buffered images. Let us name it BufferedImageLoader
  • A resource manager which manages the images read by the BufferedImageLoader and other resources like sound etc
Here is the BufferedImageLoader class:
public class BufferedImageLoader {
    private BufferedImage image;
    public BufferedImage loadImage(String path) throws IOException {
        image = ImageIO.read(getClass().getResource(path));
        return image;
    }
}
If you look at the class above, it just reads an image from the classpath and returns it. Here is the ResourceManager which will have methods specific to various resources. Resources are various images/sound resources like sprites or .wav files.
public class ResourceManager {
   private BufferedImage backgroundImage;
   public void initialize() {
      BufferedImageLoader loader = new BufferedImageLoader();
      try {
         backgroundImage = loader.loadImage("/background.jpg");
      } catch (IOException e) {
         e.printStackTrace();
      }
   }
   public BufferedImage getBackground() {
      return this.backgroundImage;
   }
}
The Texture Class
This class is a wrapper over our ResourceManager class and provides back images in terms of games objects. For e.g this class can get you an array of enemies, player, bullets etc. Remember, the Resource Manager just stores the full images and it doesn't know about the game entities. The Texture class will simplify our lives in that term. Here is a simple Texture class.
public class Texture {
   private BufferedImage background;
   public Texture(ResourceManager _rm) {
      this.background = _rm.getBackground();
   }
   public BufferedImage getBackground() {
      return this.background;
   }
}
Initializing the ResourceManager
In the initialize method of our FSM which we wrote in last post, instantiate the ResourceManager and initialize it as below:
   _rm = new ResourceManager();
   _rm.initialize();
We need to initialize the Texture as well _tx = new Texture(_rf);

The Start State

This is the first state of our game, it is visible when the game starts. The Start State needs to have the texture to access all the images in the game. So modify the constructor of the StartState to accept the Texture.
public StartState(Texture tx) {
   super(StateName.START, tx);
   this.texture = tx;
}
Let us add a flash screen to the Start State of the game. Create a Flash Screen game object and draw the background.
public class FlashScreen extends GameObject {
   int WIDTH = 1000;
   int HEIGHT = 9 * WIDTH / 12;
   BufferedImage background = null;
   public FlashScreen(Texture tx) {
      super();
      this.texture = tx;
      this.background = tx.getBackground();
   }
   @Override
   public void tick() {
   }

   @Override
   public void render(Graphics g) {
      g.drawImage(background, 0, 0, WIDTH, HEIGHT, null);
   }
}
Rendering the Background
If you run the game class now, you will just see a black screen. Let us place the background.jpg in the src directory first. So that it is available to read. In the start state, we can now create a FlashScreen instance and in the render method of StartState, we can invoke the render of FlashScreen. And we are done! we can now see our background on the game canvas. This took some more time because we wrote lot of infrastructure classes following our design and now things will be easy to create and draw as the setup is complete.

Source Code

As always, I have synced the code in Github. You can grab it from @ Github Repo

Conclusion

In this post, we had setup resource manager and were able to draw the background and discuss a bit about game objects. This was pretty cool, and next I plan to show some state transitions from Start to the New Menu state and other menu states. Which will help us choose states and play or exit game. Don’t forget to subscribe to TechieMe to get updates on latest posts.