Game Models – A Different Approach (Part 2)

The last time we talked about inheritance-based game models, which seem to be the most obvious approach to implementing game objects and logic. We pointed out many of their disadvantages, which essentially boil down to the diamond problem and the fact that all changes in your code propagate along your class hierarchy, making the whole model difficult to understand, maintain and extend.

In this part of the series I’d like to take a closer look at an aggregation-based game model which is popular since Gas Powered Games’ Dungeon Siege, but has been introduced long before. This approach tries to handle the problems of inheritance-based models mentioned before, while providing great extensibility and flexibility at the same time.

Aggregation-based Game Models

“There are probably hundreds of ways you could decompose your systems and come up with a set of classes […], and eventually, all of them are wrong. This isn’t to say that they won’t work, but games are constantly changing, constantly invalidating your carefully planned designs. […] So you hand off your new Game Object System and go work on other things. Then one day your designer says that they want a new type of “alien” asteroid that acts just like a heat seeking missile, except it’s still an asteroid.”

– Scott Bilas

The idea is to implement all game entities as aggregations of components, which in turn encapsulate independent functionality. This corresponds to recommendations by the Gang of Four, who suggest “favoring object composition over class inheritance”. A similar approach is used by the Unity3D game engine, for example.

Let’s assume that we have implemented three components that are to make up our game entities: PositionComponent, HealthComponent and AttackComponent. Most of our entities will have at least the first component attached, for they have to be located somewhere in our game world. Many of them will have a HealthComponent attached as well, such as trees, buildings or soldiers that can be targeted and attacked. The AttackComponent is added to all fighting entities, e. g. knights and watchtowers.

Aggregation-based Game Models – Naive Implementation

The first and most basic implementation of our game model is straight-forward: Just create an Entity class and add references to all available components.

This approach has obvious disadvantages. Many of the component references will be null pointers for most entities, causing a big unnecessary memory overhead. Additionally, the Entity class has to be updated each time a new component is introduced.

Thus, more experienced object-oriented programmers will come up with the idea of introducing a common base class for components soon: Entities will then just hold a collection of Component objects, reducing the memory overhead and increasing extensibility. This modular approach already gets close to an optimal solution, as it is easy to build, maintain and debug, and it’s easy to implement new design ideas without breaking existing code.

However, we can do better.

Entity Systems

“All the data goes into the Components. All of it. Think you can take some “really common” data, e. g. the x-/y-/z-coordinates of the in-game object, and put it into the Entity itself? Nope. Don’t go there. As soon as you start migrating data into the Entity, you’ve lost. By definition the only valid place for the data is inside the Component.”

– Adam Martin

Next approach: There is no Entity class at all.

Whoops… How is that supposed to work? Let me explain the architecture of this system first, I promise I’ll explain its advantages (and disadvantages) later.

In entity systems, our game entities are nothing more than just an id. There is no Entity class, and thus no data or methods on entities. Furthermore, there are no methods on components, either. Our components are just containers for data of our game model, all functionality goes into what is called a system. There’s a dedicated system for each part of our game, such as a PhysicsSystem, a HealthSystem or a FightSystem. These game systems are responsible for creating and removing components for all entities, and entirely operate on their corresponding components.

Let’s just assume a new knight with the entity id 337 has been created in our game. This will cause our PhysicsSystem to create a new PositionComponent and somehow map the id 337 to this component. The HealthSystem and the FightSystem will do the same, creating and mapping a new HealthComponent and AttackComponent, respectively. All of these components are properly initialized, setting the knight’s position, health and attack damage.

If our brave warrior gets attacked now, the FightSystem notifies the HealthSystem that the knight with id 337 is to take damage. The HealthSystem will look up the HealthComponent for entity id 337 and reduce the knight’s health, maybe applying armor or other fancy stuff. If the knight’s health has been reduced to zero, the HealthSystem fires an EntityKilled event, notifying all other systems that the entity has died and its components can be  removed.

Advantages of Entity Systems

The naive aggregation-based model has one problem I kept quiet about: Adding and updating component in an arbitrary order can lead to subtle issues. You don’t want one entity to update physics before animation, and another one the other way round, for instance. While the naive model requires you to enforce a specific update order on all component collections, this is already implied by the update order of our newly introduced systems.

And there are other upsides as well:

  • Memory management. Using systems, components can easily be pooled and re-used whenever an entity has been removed, saving much time that would have been spent on memory allocation otherwise.
  • Multi-threading. Independent systems can be updated by separate threads. This can – and will – give a significant performance boost, as modern game hardware tends to provide more and more CPU cores nowadays.
  • Serialization. As there’s no entity class and all data is held by the components, this data can easily be serialized and stored in a database. That’s the reason why many modern online games are based on entity systems, using one table for each component type.

Disadvantages of Entity Systems

The most obvious downside to entity systems is the performance hit that is caused by all the look-ups. Resist the urge to add cross-component references, as this will make you lose all of the advantages mentioned above. If you think about making your HealthComponent reference a VisualEffectComponent for displaying a nice particle effect every time our fellow knight is hit, remember that there could be several VisualEffectComponents attached to the knight… In most cases, just firing an event and making the event system do its job is still the best idea.

In order to avoid running into performance issues, just don’t flood your system with unnecessary component types: Think carefully about introducing a new component, just as you would when introducing a new subclass in inheritance-based models.

One might argue that it takes longer to “get the job done” with such a system, as it looks like you’ve to think much about your architecture before you’re able to see any results. I disagree: Our team has used an aggregation-based game model at the InnoGames Game Jam a few weeks ago, and pumped out a multi-platform multi-player real-time tactics game in just 48 hours. Spending the little extra effort at the beginning pays off. Always.

Conclusion

Knowing that inheritance-based game models show a lot of disadvantages, we have taken a look at aggregation-based models and their up- and downsides. Entity systems are easy to maintain and debug, and they provide great extensibility without the necessity of modifying existing code all the time. They show better performance characteristics for both memory and CPU load, and allow you to add scripting and serialization with a minimum of additional effort.

Whenever you’re working with this kind of system, feel free to pass by and share your feedback in the comments, I’m looking forward to hearing from you!

References

Game Models – A Different Approach

It’s been quite some time since the InnoGames Game Jam #3 where I’ve been working together with – and learned a lot from – Christian Oeing. It was the first time I heard about component-based game models, and I’ve spent a lot of time learning more about this approach to game programming since then.

My intention was to pump out a huge blog post summarizing all advantages of this type of game architecture, but as it turned out, there’s a quite a lot to consider, and so I decided to start a small post series about this topic. In case you’ve never heard of entity systems in games, I advise you to read this series (and its references) carefully, because it’s very likely to make your programming life a lot easier. The last I’d like to add before we dive right in: Please feel free to share your opinion and any feedback in the comments, I’d love to hear from you.

Preliminaries

“So let’s get into the main topic here. Say you’re an engineer set out to create a new Game Object System from scratch, and you’re going to ‘do it right the first time’. You talk to your designer and say ‘What kind of content are we going to have in this game?’ They respond with ‘Oh lots of stuff, trees, and birds, and bushes, and keys and locks and … <trailing off>’ and your eyes glaze over as you start thinking of fancy C++ ways to solve the problem.

The object oriented programming sages tell you to try to determine Is-A relationships and abstract functionality and all that other fun stuff. You go to the book store and buy a C++ book just to be sure, and it tells you to fire up your $5000 UML editor. […]”

– Scott Bilas

Usually your game mainly consists of some sort of game entities: An entity is an object in your game world that can (or cannot) be visible, move around, attack, explode, be targeted, become selected or follow a path, just to name a few. This could be anything from a unit in a classic real-time strategy game to a projectile in a first-person shooter. Sometimes these entities are referred to as actors or game objects, but I’ll stick to the term entity now as that’s the one being used in most references.

Inheritance

The most common approach to implement entities might be to create some kind of Entity base class and have that class and its subclasses encapsulate the main part of your game logic. The Unreal Engine 3 features a base class called Actor which provides functionality for rendering and animating game objects, playing sounds, applying physics and much more. Almost everything in Unreal is an Actor, and there are subclasses like Pawn or Projectile extending that functionality by taking damage or spawning impact effects, for example.

At first, this approach seems natural to object-oriented programmers and totally makes sense for diving right into game development, “getting stuff done”. However, it has a lot of disadvantages which are going to be a real pain in the ass as soon as your game grows and your designers come up with new, great ideas day-to-day.

First, inheritance-based game models are subject to the diamond of death: Let’s assume you create a base Entity class and add two subclasses Selectable and Destructible that provide additional functionality for units in your new kick-ass RTS game. Why? Because the player should be able to select some of your game entities, enabling him to interact with them, whereas some others such as trees or abandoned buildings are just supposed to drop down as soon as your awesome particle-loaded missile explosion puts the sky on fire right next to them.

Next, you want to introduce your first real game logic class called Unit. Units are supposed to be selectable and destructible at the same time. In most cases the language of your choice won’t feature multiple inheritance, and you’ll be forced to abandon one class and move some functionality into your Entity, increasing the overhead for all subclasses.

These game systems show three undesirable characteristics that are hard to get rid of:

  1. Code added to the root of the inheritance tree causes big overhead, as almost everything in your game is an entity.
  2. Code added to the leafs of the tree tends to get copied and thus makes your whole system more error-prone.
  3. Root and leaf classes tend to get very big and are difficult to keep track of.

And there’s another downside to this approach. Changes to the base classes propagate along your class hierarchy, leading to further drawbacks:

  • Programmers that want to implement a new feature need to understand all base classes along the inheritance tree. New programmers in the team will be afraid of breaking something whenever they try to add any tiny new feature.
  • It’s impossible to enforce calling base class functions in every overwritten function. Someone will forget it. Trust me. And you’re gonna spend your whole evening finding that one missing base.Update().
  • The deeper your class hierarchy gets, the more likely you’ll run into call order issues. Subclasses might want to perform some operations after the base class has done its job, and all of a sudden further down your hierarchy you’ll find a class that needs to do so before.

I guess all of us have experienced the above problems, and we’ve done so several times. In my next post I’ll examine a different way of organizing your game logic and point out its advantages and disadvantages in comparison to the inheritance-based model. Again, please feel free to add any thoughts in the comments while I put the remaining stuff down on paper.

(next: Game Models – A Different Approach (Part 2))

References

Schloggered!

Schlogger has finished my new banner!! WoooohooOooo!! 🙂

She’s a little bit better with Photoshop than me after all. A bit. 😉

Thank you soo much!

Comic Collab

Sorry for having been offline for such a long time – I’ve moved to a new flat, still waiting for my ISP to flip the switch. In the meantime, Schlogger invited me to participate in a comic collab with BenAnna, JeffJojo, Jo Lott, JuliaNoody, Moritz, Pete, Hiller, Lisa and Reh! The topic: Things we used to believe back when we’re kids.

Maybe I should stop coding right now and stick to do this awesome multi-layer GIMP mouse-drawing stuff. Maybe.

Twitter Digest 2

Notch vs. Batman, Carmack vs. HMZ-T1.

Mike Capps@epicactual 6:31 AM – 4 May 12

OH from my lawyer: “of all the shit that rains down on me in a day, yours is the nice little turd that I am looking forward to.” Um. Yay.

John Carmack@ID_AA_Carmack 1:25 AM – 21 Apr 12

I finally actually measured the latency on the HMZ-T1. It is 50 msec worse than a Z800. 50! I am deeply appalled.

I can send an IP packet to Europe faster than I can send a pixel to the screen. How f’d up is that?

Markus Persson@notch 10:15 AM – 11 Apr 12

When I grow up, I’m going to get myself one of those real jobs, with actual responsibility and all that stuff. It’s going to be great.

Markus Persson@notch 8:25 AM – 30 Mar 12

If you can’t decide something important, flip a coin. Your immediate reaction to the result will tell you what your innermost feelings are.

Andrew Davidson@andrewbdavidson 8:29 AM – 30 Mar 12

@notch However if your decision involves someone elses life or death be aware that #Batman will getcha.