One of the things I’ve been doing recently is transitioning from an inheritance-based to a component-based game object system. I started the project with full knowledge that component-based game object systems are better, but intentionally didn’t implement one since I thought it would be unnecessary for such a small game. It turns out that I was wrong, and since it’s something I’m very interested in and have thought about a lot, and since something similar was going on at work, I thought I’d give it a go.
Originally I had specific classes (Building, SmallHouse, Person) that handle everything about themselves (like graphics, physics, game logic) and do all their processing in a big ‘update’ method. I’ve factored out and moved around this code through several stages, keeping it building and running along the way, as it’s dangerous to just rip it out and start again. Now I’m at a stage where these classes have been replaced by a GameObject class, which owns a collection of Components, whose subclasses like PhysicsComponent and GraphicsComponent are registered with and updated by PhysicsSystem and GraphicsSystem respectively. GameObjects can be created by name from a GameObjectFactory, and object types can be created and registered at runtime, or from an XML file. So I now have an ‘objects.xml’ file that looks a bit like this:
<object name="SmallHouseDebris">
<component type="Graphics">
<property name="meshName" type="string">
smallHouse.mesh
</property>
<property name="translationOffset" type="Vector3">
0 0 0
</property>
<property name="scale" type="Vector3">
1 1 1
</property>
<property name="rotationOffset" type="Quaternion">
1 0 0 0
</property>
</component>
<component type="Physics">
<property name="size" type="Vector3">
3.8 3.8 3.8
</property>
<property name="translationOffset" type="Vector3">
0 2 0
</property>
<property name="contactGroup" type="unsigned int">
2
</property>
</component>
<component type="DestroyAfterTimeBehaviour">
<property name="timeUntilDestruction" type="float">
10.0
</property>
</component>
</object>
</objects>
What a difference! If you aren’t impressed by that, you’re either not a programmer, or you’re a programmer in a field a bit less backwards than video games.
Now, I told a bit of a fib; actually the only class I’ve completely removed is ‘Debris’, since changing everything at once would have involved a lot of copying and pasting, as a lot of the intermediate steps were actually quite ugly and verbose. But now that I’ve proven the system works for Debris, I can get rid of all the other ‘game object’ classes. Then the only C++ code I write for game objects will be for their game logic, if that can’t be reused from existing components.
As such, the visible results you can expect from this are a variety of interesting new buildings some time soonish!
This sounds like a specialised IoC container. Or have I misunderstood?
You obviously fall into the “programmer in a field a bit less backwards than video games” category
Yes, I suppose it is a similar thing. It’s not done purely to manage dependencies though, it’s a nice concept too, and great for providing optimisation opportunities and allowing multithreading.
This way, rather than updating each game object in order, you can update all the input components, then all the physics, then graphics and so on. Conceptually nice and avoids nasty multithreading problems, and allows each system to implement whatever multithreading strategy it wants, and of course is much more scaleable than putting graphics, physics etc. on their own threads (typically the number of entities is much greater than the number of systems).
Plus there are added benefits to storing types in assets – hot reloading is one of my favourites, though I’ve got a way to go before I achieve that
Declaritive component-orientated objects are very cool but I’ve yet to master how to connect components to ‘logic’ in an efficient manner, and also the best way to share state.
In CITS how do you manage the dependency of the graphics component on the updated translationOffset from the Physics component? I’ve used a ‘logic’ component (specific to a game object type) which looks-up the graphics and other components by name, casts them the expected type, and then invoke methods on them. This worked ok but it felt a little nasty with the performance and memeory overhead and error-prone not being able to strongly type references to the components.
I’m currently experimenting with a code gen approach which takes a game object structure definition (similar to your example without the data values), and builds the named Entity (eg CSmallHouseDebris), Resource (object instance data object), Factory (builds Entity instance from a Resource), ViewState interfaces and classes. Then at construction, Logic and View component instances are injected into the entity by IoC. I have a Entity, Logic, View separation. The logic component is dervied from something like ILogic.
Using this system you can’t just declare a new game object in xml and run it – you first need to perform the code gen and compilation, but you do get declaritive game objects with strongly typed references.
I’d really like to read more about your implementation if you have the time to blog it. Thanks for the article.
The above should read “The logic component is dervied from something like ILogic”
WTF! I guess this blog doesn’t like angled brackets!
ILogic OPENANGLEDBRACKET CSmallHouseDebris CLOSEANGLEDBRACKET
I was going to use < and > but if that didn’t work either I’d look like a right tit. Hmm, if the preceeding sentence doesn’t make sense either …
Hah, you can blame Wordpress’ default comment system for that
This is something I haven’t read much about on the web so far (well, nothing talking about concrete details) so I think it would indeed be fairly useful for me to write about my approach. I’ll write an article some time soon, when time permits!
In a nutshell though, although I love strongly typed and very strict languages, I’ve gone for a more relaxed system here, since what I’ve noticed through doing gameplay coding is that gameplay code tends not to really ‘fit’ that kind of system too well. I’ll eventually be adding testing and so on to verify correctness, but for now it’s a fairly simple system, with two methods of communication between components (which is part of what the ‘dependency’ you mention is about).
Firstly users of an object can request components by type, using something like:
boost::shared_ptr<T>
GameObject::getComponent();
// note you can use <code lang="cpp"> tags for code now, and don't need to escape anything within them if you do :)
Then of course they have the interface they want and can communicate directly with it. For now this is what I use for messages or requests, like “have you built yet?”. I’ll be expanding this into a proper message passing scheme later if I feel it’s necessary (and it may well be with scripting).
The other way of communicating, for continual updates like position and so on, is also very simple. Each object holds a map of properties and exposes an interface to this. Then, for example, the Physics component can set the “position” property every frame (and check for changes in case e.g. a script wants to teleport!), and later that frame the Graphics component will read the “position” property. There’s plenty of potential for typos there since they’re string IDs, but that’s what testing will be for
So it’s nothing particularly clever. If a dependency is missing, the component that needs it will just not work particularly well (the Graphics component won’t update its position if “property” is missing, or is the wrong type). Of course you could easily detect this so they’re not stealth errors.
I find code gen approaches interesting, yet… strange? I don’t know, I just don’t like the idea that there are files I control only indirectly! Also I don’t know how well that would work with data-driven behaviour like scripting – one of the reasons I’ve picked such a “string ID”-like way of doing things is that it’s super-easy to do scripting with (and requires little maintenance).
Anyway, thanks for the comment(s)!