Component Oriented Design

Prelude

I’ve been introduced (against my will… kind of) to game programming. Games have the peculiarity that some of the problems you need to solve are really interesting the first time you tackle them. Although most or all problems have already been solved, I like to reinvent the wheel and, just like the reason why I started this blog, lets re-solve a design problem.

This is basically the post I would’ve wanted to read while learning about this, not really much new here. So if you know what the title means, may be you can just skip to the code.

The problem

The “nice thing” about the design problem I’m about to comment on is that even with small games it’s likely that you bump into it.

To illustrate the problem, lets introduce two types of sprite representation that can be found in Cocos2D: CCSprite and CCSpriteBatchNode. CCSpriteBatchNode is not technically a sprite in itself, but it represents a group of sprites that use the same texture so they are drawn “at the same time”. That way you can have thousands of copies of the same object in screen and you’ll get it almost for free. CCSprite just represents a lonely sprite. Both are CCNodes and they implement a draw method, and in terms of Cocos2D this is what we care about for this problem.

So say you start your shoot’em up game implementation, you start modeling a spaceship. You might say: Spaceship is-a CCSprite, or Spaceship has-a CCSprite (and you take care of adding the _sprite the spaceship has to the tree representation so that it’s drawn). For the sake of not going crazy while writing about this, lets just say we picked the is-a representation and I’ll comment briefly the has-a case at the end.

So you’ve got a spaceship, but wait! you’ll probably have a lot of objects in your game, so lets say your hierarchy is: Spaceship is-a GameObject, GameObject is-a CCSprite.

You have the following types of spaceships: main spaceship (the one you command), a boss, and the regular bad guys that appear frequently. So, MainSpaceship (understands user input) is-a Spaceship, RegularBadSpaceship (has some kind of way of killing) is-a Spaceship, BossSpaceship is-a RegularBadSpaceship (but harder to kill).

How frequent are RegularBadSpaceships? Lets say a lot, but BossSpaceship will appear once every level. The point here is that you would want to have the RegularBadSpaceship be represented with a CCSpriteBatchNode and CCSprite for the boss… well hello problem!

The point is that when you are way down your class hierarchy design, you find yourself needing to change a kind of root node because you have a couple of particular leafs in the tree that need a special treatment. Creating a whole branch means replicating a lot of code… but say you go this way, it’s not *that* much code. Then you realize you can use batchNodes for all the sprites, and you need to change a lot of code. Or you realize you need a third way for a sprite (may be a custom drawing node, who knows), and you end up replicate more code. It will work, but this is not the way to go.

A solution

A possible solution, that I found is *THE* solution for this is a component oriented design. Every functionality is a component and a whole game object is a set of components. The component wrapper doesn’t have functionality in itself, it is what its components implement.

So, for our problem, we would have two components for displaying an object. One would use CCSprite, the other one a CCSpriteBatchNode. Both nodes would be of the same kind, so they would have the same API and you can exchange the way an object is displayed by just changing the components. Everything else will be transparent.

While designing a component, you would have dependencies between components, some optional and some not.

When handling objects, you won’t care about the actual class for the object, but wether it implements (or has-a or is-a) a component or not. “Can this thing shoot? Then shoot”, “Is this displayable? Then display”, and so on.

Nice, right? If so much text wasn’t clear enough, lets see some code.

Lets tell it in Python

Component oriented design is really nice to implement in a dynamic language like Python, where you can edit everything at runtime.

You could create a method implements() that returns a bool, and have a set with component ids (or may be a class object) and check for a component belonging to that set to resolve wether it has a component.

It may not be the best Pythonic implementation, but you get the idea.

But what about C++?

A more tricky implementation (but not so much) is in a statically typed language like C++.

Design patterns?

Wait, isn’t this just a Mixin pattern? Yes, it depends on what you want to accomplish, what language you use and how much you want to write.

There are always so many ways of doing the same.

Alternatives

So, an alternative to this inheritance madness (imagine an object with 20 components), is having a couple of helper methods or templates, a nice hash data structure and having the components as a has-a relationship. It will have more overhead, but how much is “more”? Not much in my little experience, in a language like C++, the right data structures and not a zillion components and you’re good to go. The overhead will still lie in the same old bad guys: rendering and reacting to input.

This bits of knowledge I gained throw game design headaches were a really nice lesson on framework or library designing too, or anything that may have complex inheritance trees with a lot objects that are like others but not quite.

Personally, when the time came to put this into use, I went with the alternative approach instead of the inheritance madness and the bigger the game got, the more I loved just having to deal with components and how flexible it all was.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s