Entity Component System is all you need?
This article is a sequel to my article on multiple dispatch.
The benefits of multiple dispatch become clearest when we talk about numerical or scientific code but the Entity Component System (ECS) is more popular and talked about in the game dev community.
While the scientific community and game dev community are very different, both of them share a common pain-point of working with “design patterns” that just don’t make sense to them.
Most design patterns you were taught, are design patterns to work around the shortcoming of Object Oriented Programming. They are not the “best” design patterns.
One important thing to remember is that a “slow game” is not viewed as generously as a slow website, a “slow game” is considered broken because for the most it needs to update the entire state of a game 60 times per second otherwise known as 60 FPS.
So there’s a lot we can learn from game devs about high performance code.
Game Objects and Components
The first time I heard that Unity was building a framework for the Entity Component system. My first reaction was “huh, I thought I was using that already”.
Game Objects are dead!
Use Data Oriented Design
“What do you mean Game Objects are dead? They make so much sense and I just figured out how they work!”
“I already use Data Oriented Design!”
Or so I thought
Part of the challenge is that there isn’t a clear consensus around what ECS actually is or how pure it needs to be. There are many implementations that exist which I’ve referenced at the bottom of this article.
I thought it’d be useful to zero in on how Unity defines ECS. But first we need to review the “old-school” way of doing things: Game Objects.
So suppose you’d like to move an object, then the typical way to do this in Unity is that your entity would have a reference to a Transform component. Take the coordinates from the Transform object and then change them.
And if you’d like add more behavior to this Unit, you would add new Components that take of stuff like Physics collision, rendering, light sources and anything else you’d expect a modern game engine to do
However, if you actually look at what’s defined in the Transform, it’s the below long list. Unity doesn’t really know what’s important and so anytime you’re loading the Unit or modifying it some way then your game will load all of the below into memory. And it does the same for all components.
Can we do better?
So why ECS
There are 2 purported benefits to the pure ECS approach
- Easier to maintain code
- Massive scale
If you’re willing to “mentally shift” how you make games and make them in the ECS paradigm you can create games with orders of magnitude more entities on screen as shown in the Unity Mega Cities Demo.
So let’s look at each of those benefits one by one
Easier to maintain code
In the ECS system we have 3 things
- Entities: which refer to component instances
- Components: which hold data
- Systems: which process data
Let’s look at what an ECS port of the above Game Object code would look like.
We have an Entity called Unit which holds one of my components, in this case it holds a single component called Position. And we have a System MovePosition which runs on any Entity with a Position component to move it by changing its x and y coordinates.
I’m showing pseudocode here because Unity actually introduces a lot of boilerplate in the way you setup ECS but that boilerplate doesn’t help us understand how ECS works conceptually. That said I’d suggest you check out the ECS examples by Unity on Github. I may end up doing a stream on Twitch.tv/marksaroufim about the topic since it’ll be easier for me to cover in a video format.
Whether this is actually easier to maintain, time will tell. But there are many anecdotal stories of game developers converging to ECS and writing more maintainable code with it.
When we talk about scale it helps to first identify the bottlenecks.
The short of it that Processor performance has drastically outpaced Memory performance.
So this gives us a clear answer as to how we should scale games to make them run faster and with more entities.
- Take full advantage of Processor improvements
- Intelligently exploit data locality to not have Memory bottleneck your game
“Shouldn’t most modern software already exploit multiple cores?” Here’s what my task manager looks like while I’m running Visual Studio, Unity, Dota, Chrome, Visual Studio Code and Spotify.
Contrast this to my RAM
This difference is best expressed via this meme
The advantage of the ECS paradigm in Unity is that if you use it in its purest form, then you’ll be able to get great multi threaded performance on multiple cores with great memory access patterns via the Unity Job system.
In addition, Unity has also built the Burst compiler which turns Unity jobs into efficient Machine Code. This is a good thing since working with distributed systems in general is extremely painful especially if you’re a solo developer.
The idea is that you design your game with ECS and get performance by default
I could probably have entire separate blog posts about how Unity improves memory layout, multi-threading and C# scripts in general. But I’d like to specifically focus on the memory layout improvements.
Array of Struct vs Struct of Arrays
Unity Game Objects are still object oriented classes that get both data and methods. From a memory standpoint all the data with that Game Object is then spread across the heap instead of holding the data you actually need.
In the case of the Unit movement example above, we only really needed the x and y coordinate to do what we needed. The rest was bloat.
This is the default in Object Oriented Programming when you’re holding references, you can’t really do caching very well.
Instead of having an array of structures you can have a structure of arrays which gives you much better data locality and as a result better cache performance. All you need to do as a user, is write your game with ECS.
ECS is like an in memory data base for games so you can run queries on Entities instead of linearly searching over your all your Entities
Pure ECS is still not the default way to program in Unity so I still think I’ll be using Game Objects for my personal projects which for the most part don’t have millions of entities on screen.
But to be clear, if you’re working with a VR game or large scale strategy or simulation game, you should invest the time to learn ECS because you’ll need all the frames per second you can get.
However, I’ve never been a fan of Objected Oriented Programming for the simple reason that it couples data with behavior. The Data oriented approach is a powerful paradigm and I’m sure we’ll see it grow in popularity even outside of games. React.js developers seem to agree!
I’ll be be keeping a close eye on ECS in Unity and once the barriers to entry are a bit lower, then I can imagine myself shifting to ECS for good.
There are tons of references about ECS, they’re all good. My article was meant as an intro that’ll help you explore and enjoy the other references. I’d strongly suggest you check out my favorite references and if you’re still interested check out the rest.
Also if you end up using ECS for a non gaming related project, I’d love to hear about it!
My favorite references
- My favorite Design Pattern book: https://gameprogrammingpatterns.com/
- A 7 min introduction to ECS (Video): https://www.youtube.com/watch?v=2rW7ALyHaas
- Unity DOTS Explained (Video): https://www.youtube.com/watch?v=Z9-WkwdDoNY&ab_channel=CodeMonkey
- Awesome Data Oriented Design: https://github.com/dbartolini/data-oriented-design
- Designing a game with ECS in Rust: http://bfnightly.bracketproductions.com/rustbook/chapter_0.html
- Unity tutorial (Video): https://learn.unity.com/tutorial/entity-component-system#
- Robust ECS framework implemented in C++: https://github.com/skypjack/entt
- Tiny ECS implementation with falling balls demo: https://austinmorlan.com/posts/entity_component_system/
- Jonathan Blow commentary on ECS (Video): https://www.youtube.com/watch?v=4t1K66dMhWk&ab_channel=JonathanBlow
- ECS in Rust talk (Video): https://www.youtube.com/watch?v=aKLntZcp27M
- ECS code samples by Unity (with unfortunately still too much boilerplate): https://github.com/Unity-Technologies/EntityComponentSystemSamples
- Awesome ECS list: https://github.com/jslee02/awesome-entity-component-system