About Impaler

Building Games Using the MVC Pattern – Tutorial and Introduction

One useful architecture pattern in game development is the MVC (model-view-controller) pattern.

It helps separate the input logic, the game logic and the UI (rendering). The usefulness is quickly noticeable in the early stages of any game development project because it allows to change things quickly without too much rework of code in all layers of the application.

The following diagram is the simplest logical representation of the model view controller concept.

Model-View-Controller pattern

Example Usage

In an example game where the player controls a robot the following can happen:

  • 1 – User clicks/taps somewhere on the screen.
  • 2 – The controller handles the click/tap and converts the event into an appropriate action. For example if the terrain is occupied by an enemy, an attack action is created, if it is empty terrain, then a move action is created and finally if the place where the user tapped is occupied by an obstacle, do nothing.
  • 3 – The controller updates the robot‘s (model‘s) state accordingly. If the move action was created, then it changes the position, if the attack, then it fires.
  • 4 – The renderer (view) gets notified about the state changes and renders the world’s current state.

What this all means is, that the models (robots) don’t know anything about how to draw themselves, or how to change their state (position, hit points). They are dumb entities. In Java they are also called POJOs (plain old java objects).

The controller is in charge of changing the models’ state and notify the renderer.

The renderer has to have a reference to the models (robots and any other entities) and their state, in order to draw them.
We know from the typical game architecture that the main loop acts as a super controller, which updates the states and then renders the objects onto the screen many times a second. We can put all the update and rendering into the main loop along with the robots but that would be messy.
Let’s identify the different aspects (concerns) of our games.

The models
  • The droid controlled by the player
  • An arena where the droid can move
  • Some obstacles
  • Some enemies to shoot at
The controllers
  • The main loop and the input handler
  • Controller to process player input
  • Controller to perform actions on the player’s robot (move, attack)
The views
  • The world renderer – to render the objects onto the screen

Creating the Project

For simplicity I have chosen the applet this time and will try to keep it very brief. The project has the following structure:

MVC – Project structure

The file Droids.java is the applet and contains the main loop.

package net.obviam.droids;

import java.applet.Applet;
import java.awt.Color;
import java.awt.Event;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class Droids extends Applet implements Runnable {

 private static final long serialVersionUID = -2472397668493332423L;

 public void start() {
  new Thread(this).start();
 }

 public void run() {

  setSize(480, 320); // For AppletViewer, remove later.

  // Set up the graphics stuff, double-buffering.
  BufferedImage screen = new BufferedImage(480, 320, BufferedImage.TYPE_INT_RGB);
  Graphics g = screen.getGraphics();
  Graphics appletGraphics = getGraphics();

  long delta = 0l;

  // Game loop.
  while (true) {
   long lastTime = System.nanoTime();

   g.setColor(Color.black);
   g.fillRect(0, 0, 480, 320);

   // Draw the entire results on the screen.
   appletGraphics.drawImage(screen, 0, 0, null);

   // Lock the frame rate
   delta = System.nanoTime() - lastTime;
   if (delta < 20000000L) {
    try {
     Thread.sleep((20000000L - delta) / 1000000L);
    } catch (Exception e) {
     // It's an interrupted exception, and nobody cares
    }
   }
   if (!isActive()) {
    return;
   }
  }
 }

 public boolean handleEvent(Event e) {
  return false;
 }
}

Running the above code as an applet does nothing more than to sett up the main loop and to paint the screen black.
There are 3 packages in the structure and the respective components will go there.

net.obviam.droids.model will contain all the models
net.obviam.droids.view will contain all the renderers
net.obviam.droids.controller will contain all the controllers

Creating the models

The Droid

Droid.java

package net.obviam.droids.model;

public class Droid {

 private float x;
 private float y;
 private float speed = 2f;
 private float rotation = 0f;
 private float damage = 2f;

 public float getX() {
  return x;
 }
 public void setX(float x) {
  this.x = x;
 }
 public float getY() {
  return y;
 }
 public void setY(float y) {
  this.y = y;
 }
 public float getSpeed() {
  return speed;
 }
 public void setSpeed(float speed) {
  this.speed = speed;
 }
 public float getRotation() {
  return rotation;
 }
 public void setRotation(float rotation) {
  this.rotation = rotation;
 }
 public float getDamage() {
  return damage;
 }
 public void setDamage(float damage) {
  this.damage = damage;
 }
}

It is a simple java object without any knowledge of the surrounding world. It has a position, rotation, speed and damage. These states are defined by the member variables and are accessible through the getter and setter methods.
The game requires a few more models: obstacles and enemies on a map. For simplicity the obstacles will have just a position on the map and the enemies will be standing objects. The map will be a 2 dimensional array holding the enemies, obstacles and the droid. The map will be called Arena to differentiate from the standard Java map and will be populated with obstacles and enemies when it is constructed.
Obstacle.java

package net.obviam.droids.model;

public class Obstacle {

 private float x;
 private float y;

 public Obstacle(float x, float y) {
  this.x = x;
  this.y = y;
 }

 public float getX() {
  return x;
 }
 public float getY() {
  return y;
 }
}

Enemy.java

package net.obviam.droids.model;

public class Enemy {

 private float x;
 private float y;
 private int hitpoints = 10;

 public Enemy(float x, float y) {
  this.x = x;
  this.y = y;
 }

 public float getX() {
  return x;
 }
 public float getY() {
  return y;
 }
 public int getHitpoints() {
  return hitpoints;
 }
 public void setHitpoints(int hitpoints) {
  this.hitpoints = hitpoints;
 }
}

Arena.java

package net.obviam.droids.model;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class Arena {

 public static final int WIDTH = 480 / 32;
 public static final int HEIGHT = 320 / 32;

 private static Random random = new Random(System.currentTimeMillis());

 private Object[][] grid;
 private List<Obstacle> obstacles = new ArrayList<Obstacle>();
 private List<Enemy>  enemies = new ArrayList<Enemy>();
 private Droid droid;

 public Arena(Droid droid) {
  this.droid = droid;

  grid = new Object[HEIGHT][WIDTH];
  for (int i = 0; i < WIDTH; i++) {
   for (int j = 0; j < HEIGHT; j++) {
    grid[j][i] = null;
   }
  }
  // add 5 obstacles and 5 enemies at random positions
  for (int i = 0; i < 5; i++) {
   int x = random.nextInt(WIDTH);
   int y = random.nextInt(HEIGHT);
   while (grid[y][x] != null) {
    x = random.nextInt(WIDTH);
    y = random.nextInt(HEIGHT);
   }
   grid[y][x] = new Obstacle(x, y);
   obstacles.add((Obstacle) grid[y][x]);
   while (grid[y][x] != null) {
    x = random.nextInt(WIDTH);
    y = random.nextInt(HEIGHT);
   }
   grid[y][x] = new Enemy(x, y);
   enemies.add((Enemy) grid[y][x]);
  }
 }

 public List<Obstacle> getObstacles() {
  return obstacles;
 }
 public List<Enemy> getEnemies() {
  return enemies;
 }
 public Droid getDroid() {
  return droid;
 }
}

The Arena is a more complex object but reading through the code should make it easy to understand. It basically groups all the models together into a single world. Our game world is the arena which contains all the elements like our droid, enemies and obstacles.

The WIDTH and HEIGHT are calculated based on the resolution I have chosen. A cell (tile) on the grid will be 32 pixels wide and tall so I just compute how many cells go onto the grid.
In the constructor (line #19) the grid is set up and 5 obstacles and 5 enemies are randomly placed. This will make up the starting arena and our game world.
In order to keep the main loop tidy, we’ll delegate the update and rendering to the GameEngine. This is a simple class that will process the user input, update the states of the models and will render the world. It is a tiny glue framework to make all these happen.
The GameEngine.java stub

package net.obviam.droids.controller;

import java.awt.Event;
import java.awt.Graphics;

public class GameEngine {

 /** handle the Event passed from the main applet **/
 public boolean handleEvent(Event e) {
  switch (e.id) {
  case Event.KEY_PRESS:
  case Event.KEY_ACTION:
   // key pressed
   break;
  case Event.KEY_RELEASE:
   // key released
   break;
  case Event.MOUSE_DOWN:
   // mouse button pressed
   break;
  case Event.MOUSE_UP:
   // mouse button released
   break;
  case Event.MOUSE_MOVE:
   // mouse is being moved
   break;
  case Event.MOUSE_DRAG:
   // mouse is being dragged (button pressed)
   break;
  }
  return false;
 }

 /** the update method with the deltaTime in seconds **/
 public void update(float deltaTime) {
  // empty
 }

 /** this will render the whole world **/
 public void render(Graphics g) {
  // empty
 }
}

To use the engine the Droids.java class needs to be modified. We need to create an instance of the GameEngine class and call the update() and render() methods at the appropriate times. Also we need to delegate the input processing to the engine.
Add the following lines:

Declare the private member and also instantiate it.

 private GameEngine engine = new GameEngine();

The modified game loop looks like this:

  while (true) {
   long lastTime = System.nanoTime();

   g.setColor(Color.black);
   g.fillRect(0, 0, 480, 320);

   // Update the state (convert to seconds)
   engine.update((float)(delta / 1000000000.0));
   // Render the world
   engine.render(g);

   // Draw the entire results on the screen.
   appletGraphics.drawImage(screen, 0, 0, null);

   // Lock the frame rate
   delta = System.nanoTime() - lastTime;
   if (delta < 20000000L) {
    try {
     Thread.sleep((20000000L - delta) / 1000000L);
    } catch (Exception e) {
     // It's an interrupted exception, and nobody cares
    }
   }
  }

The highlighted lines (#7-#10) contain the delegation to the update() and render() methods. Note that there is a conversion to seconds from nano seconds. It’s very useful to work in seconds as we can work with real world values.

Important: The update needs to happen after the delta (time elapsed since the last update) has been calculated. Also the render should be called after the update so it will display the current state of the objects. Note that the screen is cleared each time before the render (painted black).
The last thing to be done is to delegate the input handling.

Replace the current handleEvent method with the following snippet:

 public boolean handleEvent(Event e) {
  return engine.handleEvent(e);
 }

Very simple straightforward delegation.
Running the applet yields no particular exciting result. Just a black screen. It makes sense as everything is just a stub apart from the screen being cleared every cycle.

Initialising the models (world)

Our game needs a droid and some enemies. By design, the world is our Arena. By instantiating it, we have created a world (check the constructor in Arena).
We will create the world in the GameEngine as the engine is responsible for telling the view what to render.

We also need the Droid to be created here because the Arena requires it its constructor. Is good to have it separate as the droid will be controlled by the player.
Add the following members to the GameEngine along with the constructor which initialises the world.

 private Arena arena;
 private Droid droid;

 public GameEngine() {
  droid = new Droid();
  // position droid in the middle
  droid.setX(Arena.WIDTH / 2);
  droid.setY(Arena.HEIGHT / 2);
  arena = new Arena(droid);
 }

Note: Arena‘s constructor needs to be modified, so the Droid gets added to the grid before the obstacles and enemies.

...
  // add the droid
  grid[(int)droid.getY()][(int) droid.getX()] = droid;
...

Running the applet again, won’t change the output but we have our world created. We can add logging to see the result but that won’t be interesting. Let’s create our first view which will reveal our world.

Creating the first View/Renderer

We’ve put a lot of effort in creating the arena and world, we’re eager to actually see it. Because of this, we will create a quick and dirty renderer to reveal the world. By quick and dirty I mean no fancy images or anything but simple squares, circles and placeholders. Once we are happy that the game elements are in we can work on a more elaborate view to replace the squares and circles with fancy graphics. This is where the power of decoupling shines.
Steps to render the world.

  • Draw the grid to see where the cells are.
  • Obstacles will be drawn as blue squares and they will occupy the cells
  • Enemies will be red circles
  • The droid will be a green circle with a brown square

First we create the renderer interface. We use this to establish a single way to interact with the renderer and it will make it easy to create more views without affecting the game engine. To read more on why is a good idea check this and this.
Create an interface in the view package.

Renderer.java

package net.obviam.droids.view;

import java.awt.Graphics;

public interface Renderer {
 public void render(Graphics g);
}

That is all. It contains one single method: render(Graphics g). The Graphics g is the canvas that is passed from the applet. Ideally the interface will be agnostic of this and each implementation will use a different back-end but the purpose of this exercise is to describe the MVC not to create a full framework. Because we have chosen applet we need the Graphics object.
The concrete implementation looks like this:

SimpleArenaRenderer.java (in the view package)

package net.obviam.droids.view;

import java.awt.Color;
import java.awt.Graphics;

import net.obviam.droids.model.Arena;
import net.obviam.droids.model.Droid;
import net.obviam.droids.model.Enemy;
import net.obviam.droids.model.Obstacle;

public class SimpleArenaRenderer implements Renderer {

 private Arena arena;

 public SimpleArenaRenderer(Arena arena) {
  this.arena = arena;
 }

 @Override
 public void render(Graphics g) {
  // render the grid
  int cellSize = 32; // hard coded
  g.setColor(new Color(0, 0.5f, 0, 0.75f));
  for (int i = 0; i <= Arena.WIDTH; i++) {
   g.drawLine(i * cellSize, 0, i * cellSize, Arena.HEIGHT * cellSize);
   if (i <= Arena.WIDTH)
    g.drawLine(0, i * cellSize, Arena.WIDTH * cellSize, i * cellSize);
  }

  // render the obstacles
  g.setColor(new Color(0, 0, 1f));
  for (Obstacle obs : arena.getObstacles()) {
   int x = (int) (obs.getX() * cellSize) + 2;
   int y = (int) (obs.getY() * cellSize) + 2;
   g.fillRect(x, y, cellSize - 4, cellSize - 4);
  }

  // render the enemies
  g.setColor(new Color(1f, 0, 0));
  for (Enemy enemy : arena.getEnemies()) {
   int x = (int) (enemy.getX() * cellSize);
   int y = (int) (enemy.getY() * cellSize);
   g.fillOval(x + 2, y + 2, cellSize - 4, cellSize - 4);
  }

  // render player droid
  g.setColor(new Color(0, 1f, 0));
  Droid droid = arena.getDroid();
  int x = (int) (droid.getX() * cellSize);
  int y = (int) (droid.getY() * cellSize);
  g.fillOval(x + 2, y + 2, cellSize - 4, cellSize - 4);
  // render square on droid
  g.setColor(new Color(0.7f, 0.5f, 0f));
  g.fillRect(x + 10, y + 10, cellSize - 20, cellSize - 20);
 }
}

Lines #13 – #17 declare the Arena object and make sure that it is set when the renderer is constructed. I called it ArenaRenderer because we will render the arena (world).

The only method in the renderer is the render() method. Let’s see what it does step by step.
#22 – Declare a cell size in pixels. It is 32. It’s hard coded as in the Arena class.
#23 – #28 – The grid is being drawn. It is a simple grid. First the colour is set to dark green and lines are drawn at equal distance.

Drawing the obstacles – blue squares
#31 – Set the brush color to blue.
#32 – #36 – Iterate through all the obstacles in the arena and for each it draws a blue filled rectangle slightly smaller than the cell on the grid.
#39 – #44 – Sets the color to red and by iterating through the enemies in the arena, it draws a circle at the respective position.
#47 – #54 – Finally draws the droid as a green circle with a brown square on top.


Note that the arena in the real world has a width of 15 (480 / 32). So the droid will always be at the same position (7, 5) and the renderer works out its position on the screen by using a unit measure conversion. In this case is 1 unit in world coordinate is 32 pixels on the screen.
By modifying the GameEngine to use the newly created view (SimpleArenaRenderer) we get the result.

public class GameEngine {

 private Arena arena;
 private Droid droid;
 private Renderer renderer;

 public GameEngine() {
  droid = new Droid();
  // position droid in the middle
  droid.setX(Arena.WIDTH / 2);
  droid.setY(Arena.HEIGHT / 2);
  arena = new Arena(droid);

  // setup renderer (view)
  renderer = new SimpleArenaRenderer(arena);
 }

 /** ... code stripped ... **/

 /** this will render the whole world **/
 public void render(Graphics g) {
  renderer.render(g);
 }
}

Pay attention to the highlighted lines (5, 15, 22). These are the lines where the renderer (view) is added to the game.
The result should look like the following image (the positions are random apart from the player’s droid):

The result of the first view

This is a great view to test out the arena and see the models. It’s extremely easy to create a new view that instead of shapes (squares and circles) displays actual sprites.

Controller for Handling Input and Update Models

So far the game does nothing but displays the current state of the world (arena). For simplicity we will update just one state of the droid, its position.

The steps to move the droid based on user input are:

  • On mouse up check if the clicked cell on the grid is empty. This means that it does contain any objects which can be Enemy or Obstacle instances.
  • If the cell is empty, the controller will create an action that will move the droid at a constant speed until it reaches the destination.
package net.obviam.droids.controller;

import net.obviam.droids.model.Arena;
import net.obviam.droids.model.Droid;

public class ArenaController {

 private static final int unit = 32;
 private Arena arena;

 /** the target cell **/
 private float targetX, targetY;
 /** true if the droid moves **/
 private boolean moving = false;

 public ArenaController(Arena arena) {
  this.arena = arena;
 }

 public void update(float delta) {
  Droid droid = arena.getDroid();
  if (moving) {
   // move on X
   int bearing = 1;
   if (droid.getX() > targetX) {
    bearing = -1;
   }
   if (droid.getX() != targetX) {
    droid.setX(droid.getX() + bearing * droid.getSpeed() * delta);
    // check if arrived
    if ((droid.getX() < targetX && bearing == -1)
      || (droid.getX() > targetX && bearing == 1)) droid.setX(targetX);
   }
   // move on Y
   bearing = 1;
   if (droid.getY() > targetY) {
    bearing = -1;
   }
   if (droid.getY() != targetY) {
    droid.setY(droid.getY() + bearing * droid.getSpeed() * delta);
    // check if arrived
    if ((droid.getY() < targetY && bearing == -1)
      || (droid.getY() > targetY && bearing == 1)) droid.setY(targetY);
   }
   // check if arrived
   if (droid.getX() == targetX && droid.getY() == targetY)
    moving = false;
  }
 }

 /** triggered with the coordinates every click **/
 public boolean onClick(int x, int y) {
  targetX = x / unit;
  targetY = y / unit;
  if (arena.getGrid()[(int) targetY][(int) targetX] == null) {
   // start moving the droid towards the target
   moving = true;
   return true;
  }
  return false;
 }
}

The following breakdown explains the logic and important bits.

#08 – The unit represents how many pixels are in a cell which represents 1 unit in world coordinates. It’s hard-coded and not optimal but for the demo is good enough.
#09 – The Arena the controller will control. It is set when the controller is constructed (line #16).
#12 – The target coordinates of the click in world units.
#14 – It is true when the droid is moving. This is the “move” actions’ state. Ideally this should be a stand alone class, but to demonstrate the controller and keep it concise, we’ll hack an action together inside the controller.
#20 – The update method that updates the position of the droid according to the time passed at a constant speed. It is extremely simple, it checkes both X and Y positions and if they are not the same as the target position, it updates the droid’s respective position (X or Y) considering its speed. If the droid is in the target position, then the move state variable is updated completing the move action.

This is not a very well written action, there is no collision checking on obstacles or enemies found along the way, no path finding. It just updates state.

#52 – The onClick(int x, int y) method will be called when the “mouse up” event occurs. It checks if the clicked cell is empty and if so, then it starts the “move” action by setting the state variable to true
#53-#54 – Converts screen coordinates to world coordinates.
This is the controller. To use it, the GameEngine needs to be updated.

The updated GameEngine.java

package net.obviam.droids.controller;

import java.awt.Event;
import java.awt.Graphics;

import net.obviam.droids.model.Arena;
import net.obviam.droids.model.Droid;
import net.obviam.droids.view.Renderer;
import net.obviam.droids.view.SimpleArenaRenderer;

public class GameEngine {

 private Arena arena;
 private Droid droid;
 private Renderer renderer;
 private ArenaController controller;

 public GameEngine() {
  droid = new Droid();
  // position droid in the middle
  droid.setX(Arena.WIDTH / 2);
  droid.setY(Arena.HEIGHT / 2);
  arena = new Arena(droid);

  // setup renderer (view)
  renderer = new SimpleArenaRenderer(arena);
  // setup controller
  controller = new ArenaController(arena);
 }

 /** handle the Event passed from the main applet **/
 public boolean handleEvent(Event e) {
  switch (e.id) {
  case Event.KEY_PRESS:
  case Event.KEY_ACTION:
   // key pressed
   break;
  case Event.KEY_RELEASE:
   // key released
   break;
  case Event.MOUSE_DOWN:
   // mouse button pressed
   break;
  case Event.MOUSE_UP:
   // mouse button released
   controller.onClick(e.x, e.y);
   break;
  case Event.MOUSE_MOVE:
   // mouse is being moved
   break;
  case Event.MOUSE_DRAG:
   // mouse is being dragged (button pressed)
   break;
  }
  return false;
 }

 /** the update method with the deltaTime in seconds **/
 public void update(float deltaTime) {
  controller.update(deltaTime);
 }

 /** this will render the whole world **/
 public void render(Graphics g) {
  renderer.render(g);
 }
}

The changes are highlighted.
#16 – Declare the controller.
#28 – Instantiate the controller.
#46 – Delegating the mouse up event.
#60 – Call the update method on the controller.
Run the applet and you can click on the map and if the cell is empty, the droid will move there.

Excercises

  • Create a view that will display images/sprites for entities instead of the drawn shapes.
    Hint: Use BufferedImage to achieve that.
  • Extract the move action into a new class.
  • Add new actions (attack) when an enemy is clicked

    Hint:Create a bullet entity that gets fired to the target. You can use the move action with a higher speed. When the hitpoint gets down to 0, then the enemy is destroyed. Use a different image to represent different states.

Source Code

https://github.com/obviam/mvc-droids or download as zip file.

You can also use git
$ git clone git://github.com/obviam/mvc-droids.git

Reference: Building Games Using the MVC Pattern – Tutorial and Introduction from our JCG partner Impaler at the Against the Grain blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

2 Responses to "Building Games Using the MVC Pattern – Tutorial and Introduction"

  1. Daniel Klava says:

    Hello there!

    Excellent article, I’ve been following them for practice, it’s been really helpful.

    I’m having trouble porting it to Android. I’m trying to use the basic loop you explained in the other post with the MVC Pattern explained here, and learning a lot with it, but I got a little stuck. What would be a simple way to accomplish this, if I may ask? Use a Canvas instead of the Graphics object?

    Thanks in advance!

  2. ishrat says:

    why don’t you provide some more tutorial for game development for us who are new in this field…it would be benefited for us..

Leave a Reply


+ five = 13



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close