Mar 29, 2008

Dependency Injection in Games

Games and OOP

Only a few domains map to a programming paradigm so directly as computer games and object orientation. A Game class matches the concept of a virtual world where several different instances of a GameObject class reside. The simulation usually consists of a loop inside the Game class with three main goals: collect and interpret user or network input; update each GameObject instance based on input and/or a simulation step; draw visible game objects on the output device.

Inheritance vs. Composition in game objects (Deja-vu):

To represent different types of simulated objects, the programmer usually create subclasses of GameObject. There are problems with the inheritance approach since objects from different hierarquies sometimes have common functionality and characteristics. This is a common issue in object oriented software design and replacing inheritance by composition is strongly recomended [check previous posts]. The GameObject class then consists only of an unique identifier, some common attributes all game objects have such as position and orientation and, most important, a collection of components. Each class implementing the GameComponent interface represents a different aspect/behavior of a GameObject such as visuals, physics, AI or health, depending on game being implemented. These components are highly flexible and easier to maintain while also maximize code reuse with many of them being useful in several different game genres.


What is the problem with inter-dependent components?

Composition also has its drawbacks, mostly when there's some coupling between components. For example, an AI component commonly depends on the existance of a health component to decide actions to take and also on a physics component to apply movements to. These dependencies are normally solved directly by the programmer, as shown in the following Java code, part of an AIComponent class, adapted from C++ example Cris Stoy put in his excelent article in Game Programmin Gems 6:


1 public void update() {

2 GameObject owner = getOwner();

3 HealthComponent health = owner.getComponent(HealthComponent.class);

4 if (health != null) {

5 // take appropriate actions

6 }

7 }


Aparently there's nothing wrong with this code, but a closer inspection shows that:


a) lines 2-4 have nothing to do with the expected game logic of an AI update, being just boilerplate code;

b) if no instance of HealthComponent is initialized for this particular GameObject, no proper AI action (line 5) will ever be taken, making it hard to debug.

How to circunvent that?

What I think is a good idea is the use of dependency injection [check Martin Fowler's article] to automatically take care of the coupling between game components and safe initialization. The programmer will not need to manually check for dependencies or their nullability. It is easier to concentrate on the game logic to implement by replacing the above code with this:

1 @Inject(nullable=false)
2 private HealthComponent health;
3 public void update() {
4 // take appropriate actions
5 }

The above code is smaller, considerably cleaner and also safer since our framework will stop initialization and show an error log if there is no HealthComponent initialized for the GameObject that owns this AI component. With this approach we believe one can write better code and achieve faster prototyping which is always desired in game production pipelines.

In the next post more details about how GCore uses dependency injection to safely initialize game objects and its components...

1 comment:

Luks said...

ainda irá demorar um tempo p/ eu alcançar esse estado da arte de programação p/ games, mais o pouco de conhecimento nessa área já me mostraram o poder de OO aplicada à área. Ainda não abordei profundamente essa interdependência entre os objetos em um game, mais já obtive êxito em abstrair tudo através de interfaces, modelando comportamentos entre os componentes de um games. Sinceramente não sei se isso é correto, afinal de contas, é tentando que se aprende