When programming Rabbit Wars back in 2007, I ended up with huge objects for each of my game entities. They handled player input, AI, moving, shooting, health points and rendering. I didn’t like it, it drove me mad. But then I came across this Evolve Your Hierarchy article. Since I was still in the middle of programming, I refactored my game entity code to use components instead of multiple inheritance (just like the article described). It worked great, my code was readable again.
Now, when writing a specific game, you can get away with having a few non-generic hacks to get things working. Sometimes you have to be practical, no big deal (good enough is, well… good enough).
But now I’m writing RPG Playground, a game editor. And because it’s a game editor and not a game, I really need to take care of making my entities and components generic.
The thing is, when I look at the current state of Entity Component Systems (also called ECS) and my own game architecture, they seem to have diverged. I’m more of a high-level, top-down kind of guy, and not so much into low-level, bottom-up reasoning. So I don’t really care how data is organized in memory, or getting the last bit of performance out of C or C++ code. And while the current Entity Component Systems seem to lean towards a more technical solution, my system is more conceptual. It might not be as optimized, but in my opinion doesn’t break Object Oriented Programming, and better supports reusing existing game libraries.
You can find a good explanation of the current state of Entity Component Systems at Richard Lord’s What is an entity system framework. So go and read that first (yes, it’s long). Don’t worry, this page will still be here when you finish that article… I’ll wait… . The next few paragraphs will refer to that article.
So, the problem we want to solve is basically the same: First the huge game loop. I actually solved this without using components, but then you end up with multiple inheritance and huge entity classes, which is also not exactly what you want. So both of our solutions use entities that are composed out of components, entities that are just containers for components. But the difference lies in components themselves.
When Richard splits the components into view, position, rotation, velocity and angular velocity, that’s already one step too far for me. And it’s probably at this point where our architectures start to divert.
When I was thinking about the different components, I ended up with 3 functional types of components. The first one is pretty obvious. Games are tiny simulated worlds, so game items have a position, velocity, etc. I call all items inside this simulated world ‘models’. They all adhere to the rules of the game world. But it won’t be much of a game if they weren’t displayed onto the screen. So a game entity also contains rendering functionality, for which I call the component that handles it ‘view’. And you can probably also guess the last type: ‘controller’. This is player input and AI that influences certain models inside the game world. Yes, you end up with model-view-controller components (like described in my blog post explaining MVC game engine architecture).
And you know what else I find weird about putting position, velocity and angular velocity in different components? Because there are tons of great physics engines out there which already handle this functionality. I don’t have (or event want) to keep track of all these properties individually. My ‘model’ component contains a physics bodies, which is registered to the physics engine. I don’t handle it myself, I outsource it.
So how does the view component know about the position of game items? Well, that part I also find strange about current entity component systems. In that system, components ‘share’ properties. Since components don’t know about each other, they share the same properties. They actually see this as an advantage that components don’t know about each other, but in my opinion, it breaks logical reasoning. It seems obvious to me that a view knows about the model to be able to render itself onto the screen. And that a controller knows about the model that it manipulates.
So instead of sharing properties (which from an OOP standpoint might also raise some eyebrows), I want to encapsulate certain properties inside the model component (which are further encapsulated by the physics library), and the view uses the model component to get the relevant info.
And if that wasn’t enough, they take it even further: split data and functionality! Thank god we all agree that this breaks Object Oriented Programming. These entity systems seem to use the strategy pattern to support different functionality. Well, in my system, the component just specifies its own functionality, in a good old Object Oriented way, and encapsulated.
Don’t ask me how such a ECS uses an external physics engine for example. I guess they try to synchronize their own component data with the body properties delivered by the physics engine, I don’t know. Or they just write their own physics engine because 3rd party libraries aren’t good enough. The typical NIH syndrome ;).
Anyway, from a conceptual standpoint, it feels wrong. It also breaks Object Oriented Programming, which probably also contributes to the weird feeling I have when looking at that architecture.
When I was young I would probably call the current Entity Component System wrong, but now that I’m older, I realize everything has advantages and disadvantaged. The obvious advantage is performance, as also mentioned in Misconceptions of Component-Based Entity Systems:
There are multiple reasons for this and the biggest is performance.
But as said before, I prefer a good conceptual architecture, which allows easy reasoning, above an architecture that tries to pull the last bit of performance out of the hardware. Yes, I make old-school 2D games, I can afford that. Besides, since I use external libraries for physics and rendering, I leave optimization to the bit-loving C/C++ programmers that wrote the library. (I love those guys, because they love the work that I hate).
Now that I gave you some indication on how my entity component system differs from others out there, I still haven’t gone into details. But because this (ranting) article is already becoming quite lengthy, I will keep the complete explanation for a follow-up blog post. (Yes, all good series end with a cliffhanger)