Adopting a Component Model for Game Development

For Colorfull one of my goals was to explore the component design pattern for game architecture. For those of you who are unfamiliar with the pattern it goes something like this:

Instead of using inheritance to add new types of behavior to game objects, the component model seeks to extend a game object’s behavior by adding or removing components. Thus, if you want objects to be affected by gravity you might add the GravityComponent.

In this model every object in the game is an instance of the same type. What components are used to construct an entity is what distinguishes, say, the player from a NPC.

Motivation

Why should we adopt a component design? The reason is pretty straightforward. In the traditional model we start with a GameObject base class and gradually extend it to add new functionality. Thus, we might have a PhysicalGameObject and later a PlayerGameObject. The problem is that there are often concerns which cut across our hierarchy but don’t fit somewhere at the top. In these cases we end up having to duplicate logic. The component model addresses this by collapsing the hierarchy and moving behavior into components which can be added or removed as needed.

How it Works

In Colorfull our component model looked like so: Outline of the component model design pattern

Each component would implement the above interface and add additional methods as needed. For example, the RenderComponent might add Render(Graphics g). The game loop would then query each entity for it’s RenderComponent and draw things.

Benefits

In my view there are a number of benefits to adopting a component model. They include:

  • Components follow the Single Responsibility principle making them easier to maintain
  • Since components are isolated it’s easy to test each individually
  • It’s easy to add or remove behavior at runtime by adding or removing components
  • Higher re-use of code as a component can be mixed and matched as needed
  • You could possibly take advantage of spatial locality to speed up memory access
  • Lends itself well to a visual editor like Unity which trades in components

Drawbacks

That said, there are costs associated with the pattern. As you probably expect, adopting a component design leads to considerably more complicated code. Some problems include:

  • Components which depend on other components can lead to run-time errors
  • Communication between components within the same entity breaks encapsulation
  • Entity-to-entity behavior is awkward since it now goes through components
  • Duplication of state for certain component pairs, e.g. rendering and physics

Conclusion

Alright, we’ve covered a lot of ground about the component design pattern, so what can we say about things? Personally, my conclusion is that this model makes a lot of sense for a large game where different game objects may mix and match various attributes that don’t necessarily form a natural hierarchy. The ability to more easily test things is a nice side effect, too.

That said, the complexity that springs out of splitting behavior which is similar but not quite logically the same is a problem. I believe more research is warranted to look into ways to bind and constrain components in a more explicit manner — ideally complete with build time errors. For instance, we need a clear way to document the relationship between components.

Overall, I would recommend using this model for engines or more complex games, but I would hesitate to adopt it for a simpler game. Finally, it’s worth noting that moving between a traditional hierarchy and a component model is not very hard, so there’s an opportunity to start simple and refactor as things get more complex.

Comments

6 Responses to “Adopting a Component Model for Game Development”
  1. Gornova81 says:

    hi! I remember long discussion on slick forum about component system and like idea, but in your system how is done component communication ? Ideally every component act only on entity, change property here, right ?

    Did you see Spartan Framework -> spartanframework.googlecode.com

  2. Hey Gornova, I didn’t look into the Spartan framework too closely. From what I did see it appears to try to create a few high level component types such as rendering, physics, etc which I avoided. I agree with your ideal, unfortunately in my implementation each object was an Entity thus there was no interface to call for higher level operations. e.g. no FireRocket method to call for a robot. Instead you would query the entity for the RocketLauncherComponent and call teh corresponding method there. I think this is a real weakness that could use a solution.

  3. egdcltd says:

    It’s nice to see articles on game design that aren’t simply copy & paste tutorials.

  4. Andy Korth says:

    Hi Alex, You mentioned Unity3D’s component system, and I figured I’d expand on that a bit. In the last two years, we’ve done a lot of big Unity contract games- a nine month contract, a six month, and a another ~six month contract.

    We find we get decent reuse of component code across different games. The game specific code doesn’t get a lot of reuse, but code written for the editor (like utility scripts), and a few superclasses go a long way in future projects.

    In terms of reuse of components across different types of actors in the game, we see occasional reuse. Mostly we got good milage out of graphic effect components. Different textures on a particle effect or explosion script can create a really different effect, so those are used in a variety of situations.

    The downsides include the complexity you’ve mentioned. When you have a series of components you can run into ordering problems. Say you’ve got a GravityComponent, a PlayerController, and a few other things. Another entity might be a camera that’s set up to point at the player.

    If your camera movement script moves the camera before your player moves, but it renders after that, your camera’s motion won’t line up with the player’s motion. If you are relying on gravity’s effect to occur within a frame before the player jumps, reversing the order might cause a few bugs. For example, we ran into a randomly occurring bug that would make your jump way shorter sometimes.

    Unity doesn’t provide a mechanism to order the components. Even with your own system where you could order your component calls, it’s still a lot of work to plan and order your components. Furthermore, once you’ve used your GravityComponent on your player, and you need to change it to work with your AI Entities and your static crates and barrels, you’ll run into some of those breaks in encapsulation you mentioned. Or even when the GravityComponent makes no references to the other components used, you still will need to be very conscious of how they interact. In this respect, you’ve got a lot of leaky abstractions. The assumption is “add a GravityComponent to an entity or game object to make it affected by gravity”. However, without a good memory of how all the individual components work on an entity, you can easily run into underlying details that conflict. Of course, the more complicated your components, the worse this gets.

    Finally, component systems get overcomplicated for things that don’t quite belong on entities. We introduced Manager entities in our Unity projects. This would include a PlayerManager (storing the player’s score, code for leveling up, advancing, etc), a MusicManager, managers for game flow, such as determining when you’ve beaten a level, managers for controlling the spawning of enemies, and managers for our dress-up system (basically creating a skinned mesh for an entity that might be wearing a set of random clothes).

    Between these manager entities, there’s obviously a lot of communication. If you forget to add any of these managers to one of your levels, the whole thing fails to run. None of them work on their own, so individual testing or reuse would always require writing some code to separate them from the other components. The Unity system of exposing variables in the editor really only allows for this sort of development- there’s no place to put in code that’s called at a lower level than the entity stuff. This means that managers are prone to call order issues too. If your LevelManager starts the music that’s appropriate for the level you’ve loaded, then you better hope that your MusicManager code has already run.

    Fortunately, at least this problem can be somewhat mitigated by using a combination of a component system, yet still having a place for your own code so you can have fine grained control of code that doesn’t belong on any specific physical entity in the world.

    I guess that ended up a bit longer than I expected, but I hope it’s useful!

  5. I’ve been reading a lot of articles on component based architecture, and I really want to move to it after I finish my current game project. It’s a bit too late for me to try implementing it now, so I’ll have to wait a bit before I can tackle this idea. Great post though!

    Looking forward to digging through your blog.

Trackbacks

Check out what others are saying...
  1. [...] blog post stems from a discussion with Alex about his blog post about adopting a component model for his games. We discussed some of the weaknesses and challenges of a component system like the [...]



Leave A Comment