Tuesday, August 21, 2012

My go at component-based design

I recently started working on a game.  Having read a bunch of stuff about how object-oriented programming isn't very suitable for modelling game worlds, I decided that a component-based design would be better.  However, while there were many articles talking about the general ideas of component-based design, I did not come across all that many resources that presented code for a framework in which to create entities, components, and systems in.  Needless to say, I decided to write my own.

The overall structure I decided to follow was one similar to that described in T=Machine's series of blog posts on this matter.  Everything in the game world would be an entity, and an entity by itself would have no data.  All data related to the entity would be stored in components, which were to be treatable as free-form bundle-of-data classes.  Finally, there would by systems, which would go through components of a given type and update them as necessary.  An extra constraint that I had was that I wanted all of this to be type-safe with minimal runtime type-checking cost; I wasn't sure that was actually possible, but decided to give it a  try anyway.

At the moment, I have some code that does all this.  In order to keep things together I added a world class to the mix which would have the role of managing the set-up of all this, and then call the systems as necessary.     The ownership and awareness can thus be described as follows:

  • The world owns all entities and systems, and is also aware of all components.
  • The systems are aware of the world.
  • The components may be aware of the entities that they are part of.
  • The entities own their components.
This can be visualised as follows, where a normal line means ownership and a dotted line means awareness:

The lifetime of a game goes as follows:
  • A world is created.
  • All entities and components are created.  Entities must be created before their components are, but for the rest things can happen in any order.
  • The systems are set up.
  • The world is set to execute, each step invoking all systems.
  • When the game has been completed, the world is destroyed, which in turn destroys all entities, components and systems.
At the moment, every step must be individually requested.  It is therefore possible to access parts of the world from outside between steps, in order to (for example) save or load the game.  I'm not sure if I prefer this way or having everything done through systems, but it's definitely convenient to keep it this way for testing purposes.

The code can be found on Github, with this post talking about the state of affairs after this commit.  I'll probably do another post that will focus on how this system is implemented.

No comments:

Post a Comment