Today, there is plenty amount of information about how well Unity ECS performs compared to MonoBehaviour. But then a logical question appears: if it shows up so well, why any project doesn’t have ECS inside? Let’s talk about this in the article.
Well, we will start from the beginning. ECS is one of the Unity DOTS stack modules that was introduced back in 2017. DOTS includes several technologies, with the core ones as Job System, ECS, Burst Compiler, as well as other packages: Unity Physics, Unity Netcode, DSPGraph, DOTS Runtime, Unity Animation.
The heart of the stack is the Entity Component System, which includes:
- Entity – entities that live in the project;
- Component – data components that give entities various features;
- System – pure systems that work with entities and data that are inside their components.
During our webinar, we showed a demo in which ECS DOTS, compared to MonoBehaviour, demonstrates incredible performance. We got this speed of work due to the fact that each of our Entity (data container), which we can very easily find, was processed in one place within our system. Solving the same problem with MonoBehaviour, we would do this operation in Update and in each MonoBehaviour separately.
It is very important to note that the DOTS stack allows us to work with the Job System and Burst Compiler without a data-oriented development approach. Accordingly, the Job System opens the door to the world of multi-threaded work with the Unity API. Although Burst Compiler imposes certain restrictions when writing code, as a reward from LLVM we get highly optimized code adapted to the current platform. Therefore, we can conclude that ESC is not the only way to optimization and performance increase when using DOTS.
Let’s analyze when ECS is really good and useful?
- When a project has a huge number of entities with the same archetype.
- ECS gives us flexibility in logic. It forces us to think and build the project accordingly DoD. It’s important to note that often when developers see methods inside components – they mark them as a mistake. Fortunately, this is not always the case, and let’s see why. A component can have logic within it that only handles the current component’s data. For example: inside the Vector3 structure, we can find many convenient properties such as Magnitude, Normalized or the Set method. All of them are created with a single goal – to help the developer.
- Photon Quantum (deterministic high-performance ECS environment). What is the main difference between PQ and the usual Photon server that we are used to interacting with in the Unity world? It consists in the fact that in the heart of Photon Quantum everything initially lives in the entities form. You will have to work with unmanaged code in C# and in this way you will be able to migrate to ECS in Unity almost seamlessly. In fact, the application on Photon Quantum works like a large simulation, and Unity is used only as the view-layer, which means that your game can live and work in headless mode. Photon Quantum has its own pathfinding, its own physics engine, and many others. Also, Unity’s physics simulation system is bad because it’s non-deterministic. This means that with the same input data, I will not get the same results of a physical simulation. In other words, we cannot rely on such a system if physics is an important part of the gameplay in our game. Therefore, Photon Quantum has its own physical deterministic framework (same input = same results on different clients).
And when is ECS not that good?
- When you need to be prompt. From a business and development point of view, there will be more time spent on developing an application that you create when using ECS. Because you will need to come up with your system, entities, components better and longer. The amount of the actual code that you will need to write for ECS will be literally bigger compared to MonoBehaviour. Therefore, your overall development time will increase. But it is important to remember that many frameworks suffer from this (they oblige us to write boilerplate code), but at the same time, having worked more at the beginning, we get more advantages later.
- When it comes to UI and animation. Very often in the ECS demo, we see some cool stuff. But the complete project is not just one gameplay. And the important part of the result that we want to see is the animated UI. And at this moment everything becomes difficult, because if we go to pure ECS mode, for example, we have Project Tiny, then in general we have no other Rendere and we cannot render in any way, except through ECS components. This means that we will have to build the UI in the same data-oriented stack. Doing this is not very pleasant, and in principle, ECS is not very well suited for solving these problems, not to mention the complete absence of any frameworks, developments, and anything else in this direction. That’s why, it will be very difficult for you to build a UI, not to mention animation and other features that you definitely want to fill your project with.
- When there is the readability of the code issues. This is a common programming problem. The larger amount of code you have, the more difficult it is to read and the more potential bugs it has. That is, imagine if I lived in the world of MonoBehaviours, then I would have only one class, where I have certain serialized fields that I use as data, and an update loop in which my logic spins, which processes each frame. If I were doing the same task in the ECS world, then I would have at least one more component class. And there must be some other bootstrapper that will create all my ECS entities so that it all lives in the ECS world.
- When you need to connect the MonoBehaviour (where we need to render something) and the ECS worlds (where there is only data and logic). Here everyone faces this “how to make them both friends” problem. You will write various data bindings, when in fact our Views will follow some entities, the positions of which we calculate in Job Systems. After all, many systems should interact within your project, and if they are from different worlds, then the implementation of their interaction will always be a very non-trivial task. In Unity, it is important to remember that people work with scenes and content. And ECS is not yet very friendly in this regard. Imagine that we do not see anything on the screen by rendering until world entities are created in the ECS domain. Artists and game designers cannot work like this, they need “live” scenes. If we recall our Unity inspector, then in ECS it will not allow us to edit values. This is what closes the doors of opportunity for artists and designers.
How and when is it best to use ECS?
ECS in Unity is most often associated with optimization. Because when the are some problems with a huge number of Monobehaviours appear, a developer can make a decision that they switch to a data-oriented stack and start rewriting the entire project. Of course, in many situations, ECS will give you a significant result, but first, we’d advise to ask yourself a few questions:
- Are you ready to rewrite most of your project? After all, everything will not be limited by just one system, and it will pull others along like a snowball.
- Are you sure you have considered other optimization options and ECS is the only way? We faced a lot of situations when developers gave up due to performance problems. But often those tasks were solved with a couple of detailed and combat profile sessions, implementing a few new ideas. The developer, if we’re thinking from C# point of view, has so many tools: optimization of the mathematics, of the algorithms themselves, basic optimization approaches in Unity, and, finally, the Job System and Burst Compiler (without ECS yet).
– Another very important factor in deciding whether to use ECS is the stage of the project. If the project is in the early stages of development and it is possible to put in extra time to build the same task using a data-driven approach, then we’ll be more okay to do it. After all, the number of systems that will need to be changed is less. But if the project is close to completion and is already in production, it is very difficult to suspend all development and start rewriting all the code for N months.
Also, we have deadlines for our projects, and pushing any of them back can cause a potential loss of position on the market. Sometimes it’s better to focus on current business conditions and opportunities, not just the technical aspect.
Therefore, all of the info we’ve shared today can be briefly summarized in one phrase: ECS has to be used not for the sake of the ECS development concept, but for the sake of performance when the application really needs it.
And do not forget that using any new technology or framework in a project is always a risk and very important to understand and evaluate beforehand. Good luck!