As Daniele said in his last post about bosses it is a particular moment for both of us. This does not mean that we are not doing anything however. I still don’t have a personal PC (shipping to the middle of the ocean takes a long time, go figure) so I am very limited, but I like to spend downtime experimenting and, in these weeks, I have been experimenting with Entity-Component-System architectures.
If you are a developer, especially a game developer, there are good chances that you eared about ECS before. In some ways ECS is an anti-pattern to object oriented programming: instead of having your game Entities represented as objects you split them in a number of Components that have little or no relationship between them other than having the same reference ID. Then you create several Systems that are executed sequentially during the game loop, and they operate only on specific components, not the whole entity.
In that last bit lies the power of the ECS architecture. First, each system has its own list of components, thus iterating between them is usually more efficient than just iterating over every entity. Second, each system operates in a completely independent way, thus avoiding “coupling” together parts of the code that should not interact, making all interactions simpler and less error-prone.
Imagine for example three game entities from our game: Exekiel, our player character, a tile of lava and the particle effect of a spell.
Then consider these components: Intelligence, Character stats, Trap stats and Rendering output. The Exekiel entity is composed by the Intelligence, Character and Rendering components; the lava is composed by Trap and Rendering; the particle has only a Rendering component. (of course there should be more, like Position)
There are also three systems running: the Game Master, that uses Intelligences and Characters, the Trap Manager, that uses Traps and the Rendering System that uses the Rendering output component.
At every iteration of the game loop the Game Master loops over all the Intelligence components, possibly using the Character stats to resolve conflicts; the Trap Manager loops only over the Trap components, and activate them as necessary; finally the Rendering System will draw the output.
Let’s take for example the Trap Manager system. This system is completely decoupled from the rest of the game. If you take it out (just comment out the line where it is created) the game will still work! The trap will stop functioning (no one would iterate over the raps components), of course, but there would be no hidden bugs or problems. You are completely free to remove all systems one by one and test them by themselves to make sure they work correctly.
If later on you want to add a Physics system, for example, you can just create a new component, give it to the entities that require them (maybe a factory is a good idea for this? I use them for Wizard of Unica) and add Physics to the list of systems that are executed at every loop. Or, say, you want to transform your game into a frenetic action-RPG? Just alter the system that stops the time every time the User Input Component is in queue.
Of course there are trade-offs, the most important one is that ECS architectures are not intuitive, making their design a challenge. Object Oriented programming is so widespread in its use because it shortens the gap between our way of thinking and the logic of our computers. It is easier to visualize every item being a special object, with certain functionalities, than imagining a world where “there is no spoon”, only properties to be modified by a black box.
I am evaluating a shift towards an ECS architecture for Wizards of Unica. Most of the logic will remain the same but it may become very useful in the future when more systems are added and, especially, a whole lot of logic will be in place making debugging all the possible combinations a nightmare.
What are your thoughts? Care to share your experiences?
Thanks for reading.