Monday, February 14, 2011

XNA and Dependency Injection

In the previous post, we discussed the topic of XNA and Agile Software Development.
Now, let's build on this information to discuss Dependency Injection with XNA.

Note: this post includes complete code sample on CodePlex.
Download code sample here.

Dependency Injection
Dependency Injection is a simple pattern to loosely couple objects and break their dependencies.
The resulting design principle, Dependency Inversion, states: Depend upon abstractions.
Do not depend upon concrete classes.


By coupling an object to an interface instead of a specific concrete implementation, you have the ability to use any implementation with minimal change and risk. This concept is important, especially when testing an object in isolation (unit testing).

Example
As an example, let's revise the Going Beyond tutorial to demonstrate XNA and Dependency Injection.

First, isolate the components used throughout the tutorial:
Component
CameraManager
ContentManager
GameObjectManager
GraphicsManager
ScreenManager
Responsibility
manages fixed camera
manages all game content
manages all game objects
manages all graphics
manages all screens
Information
view / projection matrices
currently only 1x model
currently only 1x spaceship
all graphics properties
currently only 1x screen

Next, identify the dependencies between the components:
Component
CameraManager
GameObjectManager
GameObjectManager
ScreenManager
ScreenManager
Dependency
depends on GraphicsManager
depends on CameraManager
depends on ContentManager
depends on GameObjectManager
depends on GraphicsManager
Information
aspect ratio on graphics device
game object view / projection
load game object content
update / draw game objects
clear graphics device

Sample
The following code sample refactors the Going Beyond tutorial to render a 3D model on screen.
All logic to load, update and draw the model can be encapsulated into a single game object:

SPACE SHIP
public class SpaceShip
{
 private Model spaceShipModel;
 private Matrix[] transforms;

 public SpaceShip()
 {
  ModelRotation = 0.0f;
  ModelPosition = Vector3.Zero;
  ModelVelocity = Vector3.Zero;
 }

 // Load model and set view/projection matrices.
 public void LoadContent(Model theSpaceShipModel, Matrix viewMatrix, Matrix projectionMatrix)
 {
  spaceShipModel = theSpaceShipModel;
  transforms = new Matrix[spaceShipModel.Bones.Count];
  spaceShipModel.CopyAbsoluteBoneTransformsTo(transforms);

  foreach (BasicEffect effect in spaceShipModel.Meshes.SelectMany(mesh => mesh.Effects.Cast<BasicEffect>()))
  {
   effect.EnableDefaultLighting();
   effect.View = viewMatrix;
   effect.Projection = projectionMatrix;
  }
 }

 // Update angle of rotation.
 public void Update(GameTime gameTime)
 {
  Single temps = MathHelper.ToRadians(0.05f);
  Single delta = (Single)gameTime.ElapsedGameTime.TotalMilliseconds;
  ModelRotation -= delta * temps;
 }

 // Draw model.
 public void Draw()
 {
  foreach (ModelMesh mesh in spaceShipModel.Meshes)
  {
   foreach (BasicEffect effect in mesh.Effects)
   {
    effect.World = transforms[mesh.ParentBone.Index]
     * Matrix.CreateRotationY(ModelRotation)
     * Matrix.CreateTranslation(ModelPosition);
   }

   mesh.Draw();
  }
 }

 public Single ModelRotation { get; private set; }
 public Vector3 ModelPosition { get; private set; }
 public Vector3 ModelVelocity { get; private set; }
}
Next, build the components that do not have any dependencies:
CONTENT MANAGER
using XnaContentManager = Microsoft.Xna.Framework.Content.ContentManager;

public class ContentManager : IContentManager
{
 private XnaContentManager content;

 // Load all content.
 public void LoadContent(XnaContentManager xnaContent)
 {
  if (null != content)
  {
   return;
  }

  content = xnaContent;
  content.RootDirectory = "Content";
  SpaceShipModel = content.Load<Model>("Models/p1_wedge");
 }

 // Unload all content.
 public void UnloadContent()
 {
  if (null == content)
  {
   return;
  }

  content.Unload();
 }

 public Model SpaceShipModel { get; private set; }
}
GRAPHICS MANAGER
using XnaGraphicsDeviceManager = Microsoft.Xna.Framework.GraphicsDeviceManager;

public class GraphicsManager : IGraphicsManager
{
 private XnaGraphicsDeviceManager graphics;

 // Initialize all graphics properties.
 public void Initialize(XnaGraphicsDeviceManager xnaGraphics)
 {
  if (null != graphics)
  {
   return;
  }

  graphics = xnaGraphics;
  graphics.PreferredBackBufferWidth = 800;
  graphics.PreferredBackBufferHeight = 480;
  graphics.IsFullScreen = false;
  graphics.ApplyChanges();

  GraphicsDevice = graphics.GraphicsDevice;
  SpriteBatch = new SpriteBatch(GraphicsDevice);
 }

 public GraphicsDevice GraphicsDevice { get; private set; }
 public Single AspectRatio { get { return GraphicsDevice.Viewport.AspectRatio; } }
 public SpriteBatch SpriteBatch { get; private set; }
} 
Next, build the the remaining components that do have dependencies; here each dependent component is injected manually using constructor injection technique:

CAMERA MANAGER
public class CameraManager : ICameraManager
{
 // CameraManager has dependency on GraphicsManager.
 private readonly IGraphicsManager graphicsManager;

 public CameraManager(IGraphicsManager graphicsManager)
 {
  this.graphicsManager = graphicsManager;
 }

 // Initialize camera view/projection matrices.
 public void Initialize(Vector3 cameraPosition)
 {
  ViewMatrix = Matrix.CreateLookAt(cameraPosition, Vector3.Zero, Vector3.Up);
  ProjectionMatrix = Matrix.CreatePerspectiveFieldOfView(MathHelper.PiOver4, graphicsManager.AspectRatio, 1.0f, 10000.0f);
 }

 public Matrix ViewMatrix { get; private set; }
 public Matrix ProjectionMatrix { get; private set; }
}
GAME OBJECT MANAGER
public class GameObjectManager : IGameObjectManager
{
 // GameObjectManager has dependency on CameraManager and ContentManager.
 private readonly ICameraManager cameraManager;
 private readonly IContentManager contentManager;
 private readonly SpaceShip spaceShip;

 public GameObjectManager(ICameraManager cameraManager, IContentManager contentManager)
 {
  this.cameraManager = cameraManager;
  this.contentManager = contentManager;
  spaceShip = new SpaceShip();
 }

 // Load content for each game object.
 public void LoadContent()
 {
  spaceShip.LoadContent(contentManager.SpaceShipModel, cameraManager.ViewMatrix, cameraManager.ProjectionMatrix);
 }

 // Update each game object.
 public void Update(GameTime gameTime)
 {
  spaceShip.Update(gameTime);
 }

 // Draw each game object.
 public void Draw()
 {
  spaceShip.Draw();
 }
}
SCREEN MANAGER
public class ScreenManager : IScreenManager
{
 // ScreenManager has dependency on GameObjectManager and GraphicsManager.
 private readonly IGameObjectManager gameObjectManager;
 private readonly IGraphicsManager graphicsManager;

 public ScreenManager(IGameObjectManager gameObjectManager, IGraphicsManager graphicsManager)
 {
  this.gameObjectManager = gameObjectManager;
  this.graphicsManager = graphicsManager;
 }

 // Update each game object using GameObjectManager.
 public void Update(GameTime gameTime)
 {
  gameObjectManager.Update(gameTime);
 }

 // Draw each game object using GameObjectManager.
 public void Draw()
 {
  graphicsManager.GraphicsDevice.Clear(Color.Black);
  gameObjectManager.Draw();
 }
}
Finally, build a GameManager component to manage all interaction between the main game class and each game component listed above. Again, each dependent component is injected manually using constructor injection technique:

GAME MANAGER
public class GameManager : IGameManager
{
 private readonly ICameraManager cameraManager;
 private readonly IContentManager contentManager;
 private readonly IGameObjectManager gameObjectManager;
 private readonly IGraphicsManager graphicsManager;
 private readonly IScreenManager screenManager;

 public GameManager(
  ICameraManager cameraManager,
  IContentManager contentManager,
  IGameObjectManager gameObjectManager,
  IGraphicsManager graphicsManager,
  IScreenManager screenManager
  )
 {
  this.cameraManager = cameraManager;
  this.contentManager = contentManager;
  this.gameObjectManager = gameObjectManager;
  this.graphicsManager = graphicsManager;
  this.screenManager = screenManager;
 }

 // Initialize graphics and camera.
 public void Initialize(GraphicsDeviceManager graphics)
 {
  graphicsManager.Initialize(graphics);
  cameraManager.Initialize(new Vector3(0.0f, 50.0f, 5000.0f));
 }

 // Load all content.
 public void LoadContent(XnaContentManager content)
 {
  contentManager.LoadContent(content);
  gameObjectManager.LoadContent();
 }

 // Unload all content.
 public void UnloadContent()
 {
  contentManager.UnloadContent();
 }

 // Update each screen.
 public void Update(GameTime gameTime)
 {
  screenManager.Update(gameTime);
 }

 // Draw each screen.
 public void Draw()
 {
  screenManager.Draw();
 }
}
For simplicity, build a GameFactory to construct a single instance of the GameMananger component:
GAME FACTORY
public static class GameFactory
{
 private static IGameManager gameManager;

 public static IGameManager GetGameManager()
 {
  if (null == gameManager)
  {
   IContentManager contentManager = new ContentManager();
   IGraphicsManager graphicsManager = new GraphicsManager();
   ICameraManager cameraManager = new CameraManager(graphicsManager);
   IGameObjectManager gameObjectManager = new GameObjectManager(cameraManager, contentManager);
   IScreenManager screenManager = new ScreenManager(gameObjectManager, graphicsManager);

   gameManager = new GameManager(
    cameraManager,
    contentManager,
    gameObjectManager,
    graphicsManager,
    screenManager
    );
  }

  return gameManager;
 }
}
For completeness, here is the main game class; the GameManager now manages all game actions:
GAME
public class MyGame : Game
{
 private readonly GraphicsDeviceManager graphics;
 private readonly IGameManager gameManager;

 public MyGame()
 {
  graphics = new GraphicsDeviceManager(this);
  gameManager = GameFactory.GetGameManager();
 }

 protected override void Initialize()
 {
  gameManager.Initialize(graphics);
  base.Initialize();
 }

 protected override void LoadContent()
 {
  gameManager.LoadContent(Content);
  base.LoadContent();
 }

 protected override void UnloadContent()
 {
  gameManager.UnloadContent();
  base.UnloadContent();
 }

 protected override void Update(GameTime gameTime)
 {
  if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed ||
   Keyboard.GetState().IsKeyDown(Keys.Escape))
  {
   Exit();
  }
  gameManager.Update(gameTime);
  base.Update(gameTime);
 }

 protected override void Draw(GameTime gameTime)
 {
  gameManager.Draw();
  base.Draw(gameTime);
 }
}
Download code sample here.

Summary
The revised Going Beyond example demonstrates how to isolate components using dependency injection:
Game components are able to be tested in isolation as dependencies can be replaced by mock objects.

The biggest drawback from the code sample above, however, is that all dependent components must be constructed manually in the factory before they can be injected.

Fortunately, there is a framework component available to developers that resolves this issue:
The IoC Container. This will be the topic in the next post.

Tuesday, February 1, 2011

XNA and Agile Software Development

Agile development is a modern approach to software engineering that provides an iterative incremental framework for managing complex work. Efficiency is key: by minimizing rework and debugging, teams can more rapidly respond to changing business requirements and improve quality at the same time.

Game development, by nature, is complex and has many specialized disciplines:
  • Core Systems: engine configuration, math library, localization
  • Resources (Game Assets): audio, fonts, models, textures
  • Human Input Devices (HID): input detection
  • Collision & Physics: rigid bodies
  • Online Multiplayer: networking
  • Front End: heads-up display, in-game menus, visual effects
  • Game Play Foundations: event messaging, finite state machine
  • Game Specific Subsystems: rendering, player mechanics, cameras, AI
Therefore, each game may have many components working together and subsystems interacting with one another, many of which may depend on other components and subsystems too.

Consequently, the task of coding and testing game components in isolation can be very challenging due to the tightly coupled nature of these dependencies.

Example
Asteroids: in this simple game, the player controls a spaceship depending on input from the controller.
In order to test the spaceship's rotate and move methods in isolation, the external dependency on the controller must be broken.

Dependency Injection and Inversion of Control (IoC)
When an object instantiates another object that it depends on then this leads to poor design because it promotes tight coupling between the objects. Tightly coupled code cannot be changed easily without consequences: changes made to one object may cause other objects to break.

A better approach is to break dependencies between objects and promote loose coupling:
Loose coupling leads to better design as the software is less likely to break.

Dependency Injection is a simple pattern to loosely couple objects and break their dependencies.
The resulting design principle, Dependency Inversion, states: Depend upon abstractions.
Do not depend upon concrete classes.


By coupling an object to an interface instead of a specific concrete implementation, you have the ability to use any implementation with minimal change and risk. This concept is important, especially when testing an object in isolation (unit testing).

Inversion of Control (IoC) is a framework characteristic whereby objects, which depend on other objects, do not need to instantiate those objects; instead they get the objects they need from an external source.

IoC Container
An IoC Container is a framework component that automatically resolves all dependent references for an object: when an object is constructed, the container will instantiate all dependent objects automatically and injects them into the source object accordingly.

There are many IoC containers available to .NET developers:
However, Ninject is currently the only IoC container that is compatible with the .NET Compact Framework and will work on Windows Phone 7 and Xbox 360.

Unit Testing
Unit testing is the practice in which individual units of source code are tested in isolation. Consequently, unit tests do not measure how objects interact with dependent objects; these are integration tests.

In order to successfully unit test an individual game component, external dependencies are broken, and replaced by mock objects: fake objects that emulate real classes and help test expectations about how that class should function.

Therefore, clean unit tests should be written F.I.R.S.T:
Fast
Independent
Repeatable
Self-validating
Timely
Tests should be fast
Tests should not depend on each other
Tests should be repeatable in any environment
Tests should have a Boolean output: either they pass or fail
Tests should be written in a timely fashion

Test Driven Development (TDD)
Test driven development (TDD) is similar to unit testing except the unit tests are written before the objects they test. TDD is gaining as a development best practice because objects are designed with testability in mind: an object and its dependencies must be loosely coupled from the outset.

TDD practitioners follow these three laws:
First Law:
Second Law:
Third Law:
You may not write production code unless you’ve first written a failing unit test
You may not write more of a unit test than is sufficient to fail
You may not write more production code than is sufficient to make the failing unit test pass

Extreme Programming
Extreme Programming is a method of agile software development which advocates frequent releases with short development cycles. The focus on delivering business value within each iteration leads to increased quality and lower overall total cost.

Therefore, it seems only relevant to try and integrate agile methodologies into XNA game development. As an exercise, I would like to prototype the following agile techniques accordingly:
In conclusion, it will be interesting to see if agile development has the potential to scale using XNA!