Entity Component System for Unity: Getting Started | raywenderlich.com

In this Unity tutorial you’ll learn how to efficiently leverage the Entity Component System for more performant gameplay code.


This is a companion discussion topic for the original entry at https://www.raywenderlich.com/7630142-entity-component-system-for-unity-getting-started

There is no “.unitypackage” in the “IntroToECSStarter” project…so how to open that? Please help…

It’s a complete Unity project. Just use the Unity Hub to open it up.

Note that certain temp folders need to be rebuilt when you first open the project. Just be patient the first time. It should launch much more quickly once Unity recreates those files.

Thank you so much Wilmer…it was very helpful.

This is such an awesome tutorial, thank you so much!! I learned a lot

After some testing, Im just getting better performance results with the old system. Is anyone else in the same situation?

It shouldn’t be, but there were a few things we did in this tutorial that weren’t optimized. Some of it where we bridged between the “classic” and ECS world.

Note that we didn’t use Jobs in this tutorial which is probably where you will see quite a boost versus just the ECS implementation. If switch out some of the components for the multi-threaded equivalents you should get quite a bit of extra FPS.

We didn’t introduce Jobs in this article to limit the scope, which was already quite large. But together, ECS-Jobs-Burst, should be way, way faster than classic.

Actually same here…

I have a 3950x so 32 thread CPU w/ 64 GB of RAM.

It’s not an exact science but I measured performance by the amount of time while holding w and not shooting to get down to 60FPS.

On the non-ecs scene, it took about 80 seconds to get down to 60FPS

On the ECS scene, it took about 45 seconds to get down to 60FPS.

In other words, ECS cut efficiency in half.

As you mentioned, this code doesn’t use the burst compiler or the jobs system and of course the collision system is…simplistic.

It may also have something to do with Hybrid ECS - perhaps with Pure ECS (I did not test this), it would be faster. Perhaps converting a gameobject to a entity has some performance cost.

Nevertheless, it is interesting and I think important to note that using ECS w/o the Jobs or Burst system can have a negative impact on your game. I am currently wondering whether ECS should be used for things like projectiles, or item drops, etc. but not complex gameobjects like an RPG character unless you for some reason are creating a game with thousands of complex gameobjects.

What Unity version (and DOTS packages) are you guys using BTW? ECS shouldn’t be slower, but there is a lot of “classic” stuff in here that may be really inefficient when working with the ECS part of the demo.

It’s been about a year since I’ve looked at this but if I recall, the Shuriken particle systems did cause some slowdown. If you comment that out of the ECS project, it can run for quite a bit longer before it slows down. I only kept it in so the enemies didn’t just disappear with a whimper.

Also some other things, I think PostUpdateCommands.DestroyEntity is probably an older convention.

But most significant: the Bullet and EnemyDrone prefabs use ConvertToEntity scripts to convert from classic GameObject prefabs to ECS Entities. The newer, more acceptable way to handle conversion is to use the SubScene workflow.

I really haven’t had to time to look at this in a while but maybe when things slow down…

I used the same Unity version that the starting project was made in.

I heard someone say that entities may have some performance cost in the editor but not in the actual build. Not sure if that’s true. Didn’t the non-ecs and ecs scenes both use the shuriken particle system?

Not familiar with SubScenes yet - was going to dive into those next. Gotta rest my brain for a bit though.

Yes, ECS running in the Editor is slower than the build from my understanding.

The Non-ECS and ECS are NOT perfect side-by-side comparisons unfortunately. In the ECS version, we’re invoking the FXManager.Instance.CreationExplosion method from the DestructionSystem. Not sure if there is a performance penalty to spawning the “classic” ParticleSystem from the ECS System. Commenting those out for both ECS and non-ECS examples keeps both running above 280-300 fps on my laptop.

The ECS doesn’t beat the non-ECS by very much at all, but if you add Jobs and Burst, it should be much faster.

I was really enjoying this tutorial. But for me on 2020.2.0f1 the bullets would not render if they were converted over to entities. Any ideas what might be causing that? I tried a number of different things but could not get them to render. This is my first dive though into ECS.

I have not tried it with the latest version of Unity – honestly it may be the ECS and Hybrid Renderer versions that are the culprit.

One issue that is known: the ConvertToEntity component is on the way out. It has been replaced with the SubScene workflow.

https://docs.unity3d.com/Packages/com.unity.entities@0.16/manual/conversion.html

Unfortunately I haven’t had much time to look at DOTS or refresh the tutorial and not sure if I will be able to for a while.

You can check out my YouTube channel for slightly more up-to-date videos but even those are a little behind at this point. Hopefully DOTS will settle down a little more this year.

First, thank you very much for this awesome and very clear tutorial !
I’ve read a bunch of tutorials and explanations on ECS, yours is my Top 1 :grin:

However, I think there is a little thing you’ve “missed” :slightly_smiling_face:

Entities.WithAll<MoveForward>().ForEach((ref Translation trans, ref Rotation rot, ref MoveForward moveForward) =>

.WithAll<MoveForward>() can be removed because you are already asking an entity that has a MoveForward component as it is already present in the parameters of the ForEach method. In fact, putting a component parameter inside the ForEach method works as filter.

Also, we find the same pattern below in the tutorial when you introduce the FacePlayerSystem (which is a good example to introduce Tags,WithAll,… notions btw)

We can clean this line the same way:

Entities.WithAll<EnemyTag>().ForEach((Entity entity, ref Translation trans, ref Rotation rot) =>

into:

Entities.ForEach((EnemyTag entity, ref Translation trans, ref Rotation rot) =>

or, because we are not using the parameter entity in this system:

Entities.WithAll<EnemyTag>().ForEach((ref Translation trans, ref Rotation rot) =>

Keep going :muscle:

Nicolas

After learning some UniTask async, I’m interested in Unity DOTS. Thanks for the tutorial!
However, seems like DOTS is really for advanced user in C#. The convert thing and a disappearing gameobject make me confused (too lazy to think abstract). Well, I will try to practice for the tutorial.

Another else is, how DOTS can support addressable? Where it needs to convert as entities and instantiate manually from asset reference, does it works?

DOTS and Addressables currently are not compatible. Sorry, in fact, a lot of stuff is not compatible with DOTS yet.

It’s probably a bit off from being production read (not this year, going to guess the next product life cycle). However, this is quite a different way of working, so it doesn’t hurt to get ready.

You certainly don’t NEED to learn ECS at this point. It’s not necessarily difficult – in fact, a lot of your methods become shorter when you switch to the workflow. But yes, it is a very different way of working. It’s usually for people who have very specific memory requirements (i.e. developing for consoles, where every iota of performance and very quick start up time is needed).

Could I have a question, why we have to use NativeArray, so why we can just use normal way
like this . What is different ?.


, thanks for explain to me.

Great question. I don’t believe you need it in this case. Usually, you’ll use a NativeArray so you can send data out of a Job System.

See this tutorial for an explanation: Unity Job System and Burst Compiler: Getting Started | raywenderlich.com

This tutorial just focuses on the ECS parts of DOTS, so it’s not really all that useful here.

1 Like

I didn’t understand the part why are we using class in EnemyTag and BulletTag and not structs when these are also inheriting IcomponentData?