Hierarchy diagram
There’s better ways to organize classes in a video game than a hierarchy. Image via jurgenappelo

Game developers: don't use inheritance for your game objects

3   |

If you’re organising your game objects in a hierarchy and you have at least a mildly complicated game, you’re doing it wrong.

The reason is your objects will be far too varied and complicated in form to be accurately represented as such.

The alternative is a component model. This is very basic. Instead of having everything inheriting (e.g. Object -> MovableObject -> AnimatedMovableObject), have your GameObjects include a list of GameComponents, and delegate behaviour from the GameObject to it’s GameComponents.

This lets you choose which aspects of behaviour are present in each object without worrying about effecting others.

This idea is also expressed (with the same terminology - I was inspired) by Chris Pruett in his making of Replica Island.

The downsides of a hierarchy

In a word, you lose flexibility. As we’re all aware, a hierarchical model introduces the important constraint - by definition - that anything lower in the hierarchy includes the behaviour of the classes it inherits from.

The practical result is eventually, you’ll need to make special cases to exclude/include behaviour in your lower classes. This is messy and hard to maintain and a waste of code. Unnecessary code means unnecessary complexity and unnecessarily increasing the odds of introducing bugs.

Composition example
Composition example

An example

Take two types of behaviour. Dialog, and Animated. An object with Dialog behaviour reacts to the user touching it and invokes a dialog. An object with Animated behaviour has frames and the ability to animate.

Take two types of objects. A button and an NPC. Touching the button invokes a dialog asking the user to choose a weapon. Touching the NPC invokes a dialog where you can converse with the NPC. The NPC is an animated character. This means you have the NPC with Animated and Dialog behaviour, and the button with Dialog behaviour.

Now at this stage you could put the Dialog behaviour in a super class of both, and the Animated behaviour in the NPC’s class and all is well. But the problem arises when you have an object which does not need the behaviour of the superclass (in this case, Dialog behaviour.)

For example, say the class that represents your character on the screen is Animated, but does not invoke a dialog when touched. What class should this be? Regardless of how your classes are organised, you’d need to exclude one behaviour or the other.

The solution is simple once you have objects with components. You end up with all 3 objects as the same class, a GameObject. The button gets a DialogComponent, the NPC gets a DialogComponent and an AnimatedComponent, and the player gets an AnimatedComponent

Flexibility is the benefit and it’s big

If you came to a point where you were adding such behaviour, there’s no need to refactor your classes. You simply create a new Component and add it to the object that requires it. Also, you can add and remove behaviour on the fly. I won’t concentrate on this benefit but it’s particularly powerful.

How to code it

This is easy and rather elegant. When creating an object, you have code like:

GameObject npc = new GameObject();
npc.addComponent(new AnimatedComponent());
npc.addComponent(new DialogComponent());

Your addComponent method needs to do nothing more than add the component to, say, an ArrayList (or equivalent in other languages)

public void addComponent(final GameComponent component) {
	components.add(component);
}

Here’s the important part. Your components might need to respond to certain methods. Say your animation behaviour needs to do some cleanup when the parent object is recycled. This is also easy. You just pass along methods to all components. In your GameObject class:

public void recycle() {
	for(int i = 0; i < count; i++) {
		components.get(i).recycle();
	}
}

This may seem expensive but you won’t notice it (unless you have far too many components, which you won’t.) You can also cache the amount of components in the GameObject class easily.

The costs?

Minimal. On anything but a seriously limited device, you will not notice a performance hit. X Fleet has around 40 types of Component.

Bonus: Real code from X Fleet

Here’s a method in GameObject being delegated to its components:

public void destroyed() {
	final int count = components.getCount();
	for (int i = 0; i < count; i++) {
		components.get(i).destroyed();
	}
}

Here’s a very (very) simple Component that makes use of this delegated destroyed method to make any object that recieves the signal recycle (release resources.) This is used, for example, to make enemy ships recycle, but not the player’s ship or a wingman.

public class RecycleComponent extends GameComponent {
	public RecycleComponent(final GameObject object) {
		super(object);
	}

	@Override
	public void destroyed() {
		object.recycle();
	}
}
Get the unlike kinds newsletter
An infrequent summary of top articles in your inbox