Pure of the Pure ECS Basics

Hi,

for my next game ECS is perfect. I want to use it but i am quite confused and have some questions.

(I realy dont want to use the Conversion Workflow, at all).

How do i get an absolute empty Pure ECS Unity Project with nothing but the absolute minimum of Packages in it? (Minimum as in “When i press Play nothing happens and i dont see anything”)

Where do i define when a System should be active?
Where do i define the Order of the Systems?
It is my understanding that i can do those 2 questions in some sort of Singleton Gamemaster Gameobject. Is this correct? But wouldnt that mean that i violate Pure ECS by having Gameobjects ?

How would you guys go about events in ECS? I am not talking about those classic c# Events, but in a more general way. Example:“Player has a ring equipped that alters him. Whenever the Player takes damage, he casts an ice nova around himself that also heals allies”.
That would require a lot of systems to work, right?
The way ECS works i could not have it be Pure ECS and work within the same Frame… because if i have a Spawn system, it would make sence that the Spawn system runs very high in the SystemOrder. So when the player took Damage ( -2 hp) i would have to “queue” something for the Spawn system for the next frame…

Important: Any help is welcome because the Amount of Youtube tutorials and Documentations that i have had is crazy, I saw the Overwatch one too :slight_smile:

1 Like

Pure has lost its meaning lately, and sometimes I see people strive for it just for the status of being pure. Since it is your thread’s topic, I would like to ask what it is. Initially, there were 2 “hybrids” (= not pure) which :

  • GameObject which really stays and use a proxy to sync value with its Entity frame by frame.
  • Any usage of Hybrid package at all.

By the 2nd definition, it is impossible to be pure and see anything on the screen since HybridRenderer is named hybrid and it need the hybrid-ness to access meshes on the SCD. But at that time, there were people that name their solution “pure” even while using the renderer, they refer the pure as to there is no game objects at runtime.

Right now it seems we also get 2 "pure"s. By the old first definition, Conversion Workflow could be pure. GameObject serves as only authoring medium. When you press play, GameObject is completely converted or maybe not. (e.g. it is possible that something like Light will be left behind, and entities get a reference of it).

  • Pureness based on runtime status, if they are completely converted (100%), then it is pure. This way, if I have TMP Text floating around at runtime I guess technically would not call it pure. But if the other 85% of my game that needs performance are running in entities? Then I don’t mind this TMP Text floating around ruining/violating the pure status. Personally I don’t use “pure” because it is dumb when we talk percentage and 1% of utility GO that does not take performance could make it impure, then there is no point to strive for pureness other than for fun/geek out (which is not a bad thing if you are going for some challenge).
  • Pure as in cannot even use GameObject as an authoring medium (conversion workflow) no matter if it is completely converted or not, because the conversion process itself made it impure somehow, or a mention of GameObject (even at edit-time only) make it impure… Maybe people think it is impure because it is a bit slower when entering play mode? But with Subscenes, by design it would ship as a bunch of memory blocks with no conversion occurring on real build. That is as good as pure to me but I don’t know about others that need the other “pure”.

In my opinion the goal is we should try get the core workload of the game to entities instead of going for pure.

DOTS intended that systems are always on but if there is no work it should take negligible performance to check that it is no work for large amount of running systems. When work is detected, order of system is defined by attribute tag over the system as dependencies. Official docs recommends implicit ordering, we explicitly specify requirement what it need before this one then API solve the orders.

https://docs.unity3d.com/Packages/com.unity.entities@0.17/manual/system_update_order.html#system-ordering-attributes

2 Likes

Oh boy, where do I start. Here’s my package list, trimmed to the bare minimum:

“com.unity.burst”: “1.6.0”,
“com.unity.dots.editor”: “0.12.0-preview.6”,
“com.unity.entities”: “0.17.0-preview.42”,
“com.unity.ide.rider”: “3.0.7”,
“com.unity.platforms.windows”: “0.10.0-preview.10”,
“com.unity.render-pipelines.high-definition”: “10.6.0”,
“com.unity.modules.imageconversion”: “1.0.0”,
“com.unity.modules.physics”: “1.0.0”,
“com.unity.modules.screencapture”: “1.0.0”,
“com.unity.modules.video”: “1.0.0”

“Pure” ECS will require you to replace “com.unity.entities” with “com.unity.rendering.hybrid” but I personally think Hybrid Renderer is garbage. Way too much overhead for a simple project like mine which has at most 8 objects requiring rendering and about 6 million not. That means you’ll have to use GameObjects and IJobParallelForTransform to translate entity-side data to rendered movement and physics will require a lot of hacks.

And plus, there’s a lot of stuff that DOTS hasnt, and quite possibly cant, replicate like the UI or the Camera itself. I recommend stop thinking about “pure ECS” and more “what makes sense as an entity”. Trust me, I’ve gone down the pure ECS path a few years ago and it doesnt lead anywhere except being bogged down reinventing the wheel.

GameObjects are here to stay. It’s better to work with them and leverage the already existing tools than try to pick up the pieces Unity left us when they dropped DOTS and ran.

As for the rest of your questions, if you havent already, take a look at the package documentation:

https://docs.unity3d.com/Packages/com.unity.entities@0.17/manual/ecs_core.html

I know it’s really confusing if you never touched ECS concepts. Personally it makes perfect sense because I’ve been neck deep in Unity ECS for 2 years now and lots of trial and error fills in the holes but to a newcomer it may seem like absolute nonsense.

I recommend starting by trying to understand the ECS examples.

https://github.com/Unity-Technologies/EntityComponentSystemSamples/tree/master/ECSSamples/Assets/HelloCube

And replicating them yourself. Then try and build off of them. Sure, the cube is rotating but can I get it to move back and forth? What about keyboard inputs? And so on.

Thank you guys 5argon and Kmsxkuse very much!

I will try to the things you suggested and see how far i can come before i consider “pure” to be too pure for its own good.

The learning curve is not insignificant. I have been working with ECS for 6 months now and I’m still struggling. I’m a hobbyist, so a lot of the ECS code and examples are hard to understand. Having said that, once you see what it is that they are trying to do and you embrace their concepts and philosophies, then you can really do some amazing things. What took me 10 seconds to build with Gameobjects is currently being done in under 30 ms with entities, jobs, and burst. My project is extremely data-heavy and requires hundred of thousands of entities, but it simply wouldn’t be possible in the GO world.

To answer some of your specific questions.

Where do i define when a System should be active?
-Create a systems folder and use tags (tags aren’t technically required but i find they are very easy to use and give you more control over your filtering). If a system finds the appropriate tag or element that you filtered for then it will run that frame, if it doesn’t see anything then it won’t run. So create an element (either “pure” by instantiating if you can, or through the conversion workflow) and attach a tag to it then create a system file and filter for it. I tend to add data to my tags but it isn’t necessary.

public struct BuildIrisTag : IComponentData
    {
        public FixedString32 Ticker;
        public BlobAssetReference<DateBlobs> Dates;
    }

Then do something like this to find the elements that have this tag and run a system on it:

protected override unsafe void OnUpdate()
{
Entities.WithAll<BuildIrisTag>().ForEach((Entity entity, in BuildIrisTag buildIrisTag, in Iris iris) =>
            {
     // put all your system code here - if you want to run the system every frame then leave the tag in place, if you only want to run the system once, then add this:             
var entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
entityManager.RemoveComponent<BuildIrisTag>(entity);
      }).WithStructuralChanges().WithoutBurst().Run();
}

Put some effort into learning how to run systems with Entities.ForEach and with queries. Using Entities.ForEach | Entities | 0.17.0-preview.42
Using an EntityQuery to query data | Entities | 0.17.0-preview.42

Where do i define the Order of the Systems?

You can control the order of systems using square brackets before the system class declaration. You can also create custom orders if you need to control things closely.

[UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
    public class Build : SystemBase ...

https://docs.unity3d.com/Packages/com.unity.entities@0.17/manual/system_update_order.html

It is my understanding that i can do those 2 questions in some sort of Singleton Gamemaster Gameobject. Is this correct? But wouldn’t that mean that i violate Pure ECS by having Gameobjects ?

I have finally been able to get rid of the singleton pattern by fully embracing the tag and system methodology. I don’t know if this will work for you but it is so nice not having to figure out how to pass everything to the singleton to get things done.

Finally, understanding the concepts of ECS and actually implementing them in the way that you want is not an easy task. As I said earlier, my project is data-heavy so I have had to put a ton of effort into reorganizing how the data is handled, (mostly flattening arrays since ECS doesn’t do nested arrays). Learning the job system and how to optimize things will give you incredible speed gains. I had to start measuring things in microseconds because it was being run so fast!!

It will take you several months to link everything together, but once you do, you’ll have a hard time going back to GO. Just my opinion.

1 Like

You do not need to access the static default World EntityManager if you are using SystemBase. The extension of SystemBase already provides the current world’s EntityManager as a parameter.

protected override void OnUpdate()
{
   // In a default world, this:
   var em = World.DefaultGameObjectInjectionWorld.EntityManager;
   // Is the same as:
   var identicalEm = EntityManager;

   // check is true.
   var check = em.Equals(identicalEm);
}
2 Likes