For our first blog post we are going to talk about how we decided to organize the Burger Engine architecture.
Some of you might be already familiar with component-based architecture. It’s a flexible and reusable way to build your engine. Basically, we want to create game object based on the aggregation of several behaviors rather than relying on a classic hierarchical classes with inheritance. It has been used for some years in the game industry (Here one of the most cited article on the subject on CowboyProgramming blog) , but it has recently become a big trend over amateur/indie game development.
Even so, it’s hard to find a complete example of how to implement it, maybe because it’s not as simple and intuitive as inheritance. In this post we are going to show how we try to implement this architecture in the Burger Engine.
Component over inheritance
In a inheritance system, you will probably find this kind of architecture
And so on. You want to regroup entity based on theirs functionalities, this is why the all the MovableObject will have the Move() method in common. It’s the same for the Drive() method for the Vehicle or the Fire() method for the Weapons. Indeed you do not want to code the same thing twice. However, what happens is we want a firing vehicle, let’s say a motocycle with bazooka, do we inherit from both Vehicle and Weapon? Even if it’s possible, multiple inheritance is not recommended . Moreover, it not possible in every programming language.
So sometime you put some code into a higher parents, in the game object for example. But you will end up with an enormous blob object, not maintainable and not very efficient. Besides, not all children will need every functionality from the blob parent.
In a components based system, you remove all this hierarchy just to focus on the behavior. Each object is a complete aggregation of those behavior (component). You will have a “Render” component to display a mesh into the scene, a “Script” component to execute external actions and so on, one for each functionality.
This way, we know that each class will represent a very specific task, therefore making the code more maintainable. Beside, this is very flexible. For example, Our Bazooka-equiped motorcycle will own a “driving” and a “fire” component. But imagine that later in the development of the game, we no longer want the ability to fire. We just need to remove the component. The object will be the same as before, but will be missing all the code to fire.
In Mick West’s article, we can see several way to implement this. Because we are starting from scratch, our choice was to use a component system based on pure aggregation. Basically, we have a “Composite” component (based on a abstract component), which can hold a collection of abstract component.
The engine will hold a list of Abstract component, and will update them. Moreover as a composite can hold other composite, we can create a tree-like structure. A composite is a “node”, and can choose whether or not to update it’s leaf. This allow us to update only the the composite we really need. The other advantages is that we can “move” object as a group. Indeed the component’s transformation matrix will always be relative to it’s parents. If we apply transformation to an object, all the children will be impacted.
Last but not least, this approach is data-driven. Our engine has almost no game specific code. So far we are using external .xml files to build our object using components. Specifics behaviors can always be implements outside the code using a script and a script components. And when the time comes to create components specific for one game, you will only have a few of them.
In theory, component-based architecture is the way to go for an engine. However, we’ve come across some difficulties.
One of them is that we need to regroup component by type sometimes. Rendering for instance. We need our mesh to be sorted in a certain order for transparency. However, we do not know their order in the composite list. This is why we have sub-system, which reference the needed component.
We have a renderer, which will hold a reference to all our mesh. Then we can order them as we want. The only thing is that when a rendering component is being destroy, it needs to inform the sub-system the mesh is no longer aviaible. This is why our sub-system can be accessed throughout our engine. We have sub system for render, particle, physics and so on.
In the end, using component-based system as been as good choice to start with. It has not be easy, and we are definitely not through all our problems, but it was worth it. Once you’ve got your head around it, you can prototype and implement behavior faster and cleaner. It feels just like building object out of blocks, adding and remove functionalities.
More info on component-based architecture: