For a long time now I’ve been toying with component systems. I’ve been trying many different methods to implement one and none seemed to work for me. Then finally the other day it all clicked. Here’s the story…
A bit of a prologue:
An accurate description of how component systems are supposed to work is elusive as there are many varying opinions about how they are meant to be used. One thing is agreed, they are the way to go when developing large scale games.
The benefits of such a systems are undeniable. Imagine a game developed using object oriented (OOP) principles where each object is a defined type. Say for example we have a Vehicle class. We can extend this to be a Helicopter by adding flight functionality or we can extend this to become a Tank by adding armour and guns. What if we wanted to add guns to our Helicopter? Do we copy the code from Tank? Do we move the gun code up a level into Vehicle? Once more variations in design appear, our code gets cluttered, duplicated and misplaced. Entity component systems aim to extinguish this problem by breaking objects down to components.
Using the above example we would have a basic Entity (or GameObject as they are known in Unity). This basic object does nothing on its own except exist. We would then augment the Entity with abilities using Components. So, for example, our Tank would have a VehicleMovement component, an Armour component and a Gun component. Our Gunship will have Flight and Gun components. No duplication of code and no need to worry about the deadly diamond of doom.
There are many ways to implement such a structure. Unity and Flambé use the approach where most of the logic happens in the components which are updated each frame. Flambé promotes components extending other components and each class that inherits directly from Component becomes a new component type. The problem with these is that inheritance creeps back in and before you know it, the habits drilled into us as object oriented programmers take over; we end up using components as the objects we are used to by piling logic into them an extending them to suit our needs.
…it’s all too easy for experienced OOP programmers to keep trying to sneak some OOP back in where it’s inappropriate, and it’s all too easy to delude yourself into thinking this is a Good Idea. And, worse, from the teams I’ve worked on in the past, it has consistently seemed that the better you are at OOP programming, the harder this is to resist… [Adam from T-machine.org]
Further to that, where does the logic go when when multiple components on the entity need to interact? Should one component be allowed to access another or should they be separated to keep dependencies to a minimum? What about in complex systems such as physics where multiple entities need to interact with each other? Where do we put this code? I’d been experimenting for so long I’d actually given up and started building my new adventure game prototype in a more traditional OOP way.
And then it clicked…
I’d got part way through before running into some basic inheritance issues and then it hit me; a component system doesn’t need to be the entire basis that a game is built on. Sprites don’t need to be components. UI and events don’t need to be components. Quite simply, the components are just another data model that enhances accessibility in game code and allows the game engine to pick and choose data it needs to work with. After reading guides to confirm what I thought, I knew I’d nailed it and finally got it straight in my head.
How it works for me:
I take my approach from this excellent guide by Adam from T-machine.
Think of the game as a database. We have Entities which are actually just ids to associate a group of components and nothing more. The most important thing to note is that they do not even need to exist as classes, objects, instances or anything of the kind. Once we simplify it down to this level of thinking we see that an entity component system is actually little more than an array of components, each associated with an entity id.
Components are data structures first and foremost. They are specific pieces of information attached to an “entity” and make up the identity of an object in game. Any part of my game can access any component just by querying the ComponentsSystem class. The entire job of the ComponentsSystem class is to store components and to retrieve them when given an entity id, a type of component or both. This means that my movement system can find all components defined as a movement type, and through the ComponentsSystem, find other components associated with an entity and adjust them as required. The code for my current component system is extremely simple; it’s only around 50 lines of code.
The second most important difference between a component system and OOP is where the logic goes. Instead of having objects that know how to handle themselves when given instructions, we instead have a collection of “dumb” data objects that know nothing but a few bits of information about themselves. This is where systems come in. As previously mentioned, the movement system in my game retrieves all components of the movement type. If an entity has no movement component then it’s not moving. The movement system takes the speed and direction from the movement component and applies it to the entity. It’s as simple as that. Because all of the logic is centralised, multiple entities can interact in the system’s code without explicitly knowing about each other keeping dependencies to a minimum.
This is the way I now understand component systems and I am using this methodology while building my latest game prototype. I have no doubt this new way of thinking will be beneficial to me as a new weapon in my coding arsenal and hopefully this brain dump will help others “click” in the way I did when trying for so long to understand entity component systems.