ECS - Rebuild of Unity's upcoming - Entity Component System - FREE

Follow us on git!

Hello everyone!

I want to do something good to all of you!

I like the new ECS approach of unitys tech-team! But I cant wait for it… So I’ve build my own one, that’s similar to Unity’s upcoming.

And because of that…
It’s purposeless to sell it on the store… So I decided to publish it for FREE!
(attachment)

Whats the benefit…

  • Huge speedup in relation to the (legacy) Unity System
  • Easy maintenance and extensibility
  • System debugging like Entitas ECS
  • Inversion of control (dependency injection)
  • No Garbage Collecting (only if you do live debugging with components on gameobjects, but you can turn on and off in playtime)
  • TupleInjection for multiple components in systems (only entities that matches all tuples)
  • Easy to use components, supports structs and classes
  • Easy to extend for multithreaded Systems (but not yet implemented)
  • Fast system and component creation with templates
  • Unity monobehaviour integration
  • Supports data prefetching (fetches data before it is needed)
  • Creating entities from Prefabs
  • Supports different contextes for entity (just by creating new classes of RootSystems and EntityManagers)
  • No Object pooling required

Here is an short example of usage:
Controller Executes all the systems

namespace ECS {

    // Use this class to control the ECS System
    public class GameController : ECSController<UnityStandardSystemRoot, EntityManager> {

        // Use this for initialization
        protected override void Initialize() {
            AddSystem<MySystem>();

            // or you can use this for more controll over compositions of systems
            //AddSystem(new MySystem());
        }

        // Override this function if you want to controll what Scene Entity should be load in this context
        // The base implementation will add all Scene Entities to the context
        //protected override void AddSceneEntitiesToSystem() {
  
        //}
    }
}

It creates the system and the entity manager by dependency injection for you
With the AddSystem methods you can assign your systems to the ECSSystemRoot.
The ECSController also executes the Start, Update, and FixedUpdate Routines of the Systems

An ECS Component

using ECS;
using System;

namespace ECSExample {
    [Serializable]
    public struct FloatComponent : IComponent {
        public float value;

        public FloatComponent(float value) {
            this.value = value;
        }
    }

    public class FloatDataComponent : ComponentDataWrapper<FloatComponent> { }
}

Initialize Entity System

using ECS;
using ECS.VisualDebugging;
using UnityEngine;

namespace ECSExample {
    [DebugSystemGroup("Init")]
    class InitEntitiesSystem : ComponentSystem {

        private GameObject _gameObject;

        [InjectDependency]
        private EntityManager entityManager;

        public override void OnStart() {
            _gameObject = new GameObject("Entities");
            for (int i = 0; i < 1000; i++) {
                Entity entity = entityManager.CreateEntity();

                GameObject gameObject = new GameObject("Entity-" + i);
                gameObject.transform.SetParent(_gameObject.transform);

                GameObjectEntity goEntity = gameObject.AddComponent<GameObjectEntity>();
                goEntity.SetEntity(entity, entityManager);
                entityManager.AddComponent(entity, new FloatComponent(1f));
            }
        }
    }
}

Update float component of all entities

using ECS;
namespace ECSExample {
    [DebugSystemGroup("Update")]
    class UpdateFloatSystem : ComponentSystem {

        [InjectDependency]
        private EntityManager entityManager;
 
        [InjectTuple]
        private ComponentArray<FloatComponent> floats;
        public override void OnUpdate() {
            float sum = 0;
            for (int i = 0; i < floats.Length; i++) {
                entityManager.SetComponent(floats.GetEntity(i), new FloatComponent(floats[i].value + 1));
            }
        }
    }
}

Accessing Components in Systems

//This class see only Enities with ComponentA and B attached to it
class MySystem : ComponentSystem {
    [InjectTuples]
    ComponentArray<ComponentA> componentA;

    [InjectTuples]
    ComponentArray<ComponentB> componentB;
}

// if you want to manualy will filter components use the following:

ComponentGroup group = m_EntityManager.GetComponentGroup(typeof(ComponentA), typeof(ComponentB),...)

ComponentArray<ComponentA> compA = group.GetComponentArray<ComponentA>();
ComponentArray<ComponentA> compB = group.GetComponentArray<ComponentB>();

Instantiate from Prefab without instantiating the GameObject:

 struct Position : IComponent {
    public Vector3 position;
    public Quaternion rotation;
}

PositionComponent : ComponentDataWrapper<Position>{ }

class Spawner : Monobehaviour {
    public GameObject prefab;

    [InjectDependency]
    EntityManager _entityManager;

    void Awake() {
        InjectionManager.ResolveObject(this);
    }

   void Start() {
        // Instantiate the prefab with all its components attached to it
        Entity entity = _entityManager.Instantiate(prefab);
 
        // just update the position component
        var position = new Position(Vector3.zero, Quaternion.identity);
        entityManager.SetComponent(entity, position);
   }

}

Instantiate Entities from Prefab with instantiating the GameObject

 public class PrefabSpawner : ScriptBehaviour {
        public GameObject _prefab;

        [InjectDependency]
        private EntityManager _entityManager;

        // Use this for initialization
        void Start() {
            GameObject gameObject = _entityManager.InstantiateWithGameObject(_prefab, transform.position, transform.rotation);
        }
    }

Components that supports Unity Component

    [Serializable]
    public class ECSTransform : IComponent, ICloneable {
        public Transform transform;

        public object Clone() {
            return MemberwiseClone();
        }
    }

    [HideInInspector] // dont show inner component in Inspector
    public class ECSTransformComponent : ComponentWrapper<ECSTransform> {
        // This will assign the Unity Component to the ECS Component
        public override void Initialize() {
            TypedComponent.transform = gameObject.transform;
        }
    }

Creating of different Contexts

//context for Cars
class CarEntityManager : EntityManager{}
class CarRootSystem :  UnityRootSystem<CarEntityManager>{}


//context for Humans
class HumanEntityManager : EntityManager{}
class  HumanRootSystem :  UnityRootSystem< HumanEntityManager>{}


//usage
class Controllers : Monobehaviour {
       CarRootSystem carSystem;
       HumanRootSystem humanSystem;

       void Awake() {
            carSystem = new CarRootSystem ();
            humanSystem= new HumanRootSystem  ();

            ... add systems to the rootsystems
      }

      void Start() {
            carSystem .Start();
            humanSystem .Start();
     }

      void Update() {
            carSystem .Update();
            humanSystem .Update();
     }


      void FixedUpdate() {
            carSystem .FixedUpdate();
            humanSystem .FixedUpdate();
     }
}

This will enforce that you will separate enitities, components and systems
Systems of context Car only knows entities of that system and so on.
If you want to communicate with the other Context use the EntityManager of that context

Its almost identical to the video of Joachim Ante from Unite Austin 2017

Great thanks to him and his team!!!

It took me a week of afternoons and a whole weekend to write it that performant!
So please enjoy it and fell free to use it.

It’s not fully completed yet and tested.
I also want to implement some basic components: like transform and so on.

Here are some pics for you:
Entitas like system debugging

Enitity Debugging live in GameObjects

Easy Setup for template script integration (be aware its global)

Template Scripts


The GC pike in the image comes of enable debug mode of an entity (for confusion)

IOC:
it works with any class you want.
Just call InjectionManager.Resolve() or if the object already exist use InjectionManager.ResolveDependency(my object)

A injectable class should have the [InjectableDependency] Attribute on it
And to inject some object to your Fields and Props use [InjectDependency] Attribute
The system will automatically recognize dependencies of constructors

Example

[InjectableDependency(LifeTime.PerInstance)]
class MyClass {
... some code
}

class SecondClass {
    [InjectDependency]
    private MyClass myClassInstance;
}

class ThirdClass {
    public ThirdClass(MyClass myClassInstance) {
        ... some code ....
   }
}

... somewhere in the programm

InjectionManager.Resolve<SecondClass>();
InjectionManager.Resolve<Thirdclass>();

// or
SecondClass mySecClassInstance = new SecondClass();
InjectionManager.ResolveDependency(mySecClassInstance);

If you want to use Dependency Injection in a Monobehaviour class,
just use ScriptBehaviour instead of Monobehaviour.

    public class SomeMonoBehaviourClass: ScriptBehaviour {

        [InjectDependency]
        private EntityManager _entityManager;

}

If you have some questions, tips or hints, feel free to contact me!
Again, enjoy it!

Kind regards,
Spy-Shifty

3277532–253873–BrokenBricksStudios_ECS.zip (95.1 KB)

10 Likes

I’ve made some Updates to the documentation above like usage of different contexts, component access and so on!

It would be nice if you can give me some feedback :slight_smile:

EDIT:
I updated the zip! I found some bugs that i solved now!
There is one more with class comonent types if you instantiate them from prefab.
I’ll look how to solve that and submit a new Version. Maybe tomorrow.
I’ll also investigate time on how to integrate Unity basic Monobehaviour classes into the component system

I’ll let you know!

Ok I’ve found a solution for Unity Components and the problem with instantiating components of class type.
I also fixed some more bugs with the system debugger. I’ve added one more example for spawning GameObjects that using ECS and which are interacting with the Transform component.

And one more: I added some more lines of code for documantation at the top post in this thread.

Something to class and struct components:
class components are only introduced to support Unity Components
they should not be used in other way!

structs are much faster! Thats because of structs are valuetypes and will be stored right after each other in memory

If you use struct data, they are tightly packed right after another. The Dataprefatching will happend and that gives us a hughe performance boost.


If you use classes just the pointer to that class are packed right after another.
The instance of the class itself is far away. So to load a class somewhere in the RAM, it will takes ~100 to ~300 cycles. That is bad for performance and the reason to use structs instead.

@Spy-Shifty_1 I am impressed.

  1. How do you accomplished this in a week? Did you use any kind of framework or are you crazy?

  2. Do you see any possible problem to use this in the wide range of deployment targets, that unity provides (Mobile, Desktop, TV)? Does it work for Unity 5.4.5 and higher?

  3. You and Andy described, too use structs and fields with no reference types to keep the data inline in the memory. I am working at a moment on a solution to filter a array with a bunch of objects by values. One of the properties contains a string (for text search). But If I can not use reference types (which a string is), how would you solve this?

Hi and thank you.

1)Well I’ve been with it for a longer time. I worked with different kind of ECS Systems like Entitas and SveltoECS.
I’ve only analysed what Joachim Ante said at the Unite Austin 2017. And because I cant wait for it,… I started to write my own. So its not out of the box my ideer. I’ve only implemented what Joachim said.
Yes maybe I’m crazy :smile: and no I don’t use any framework. It’s all self implemented. (Except the visual system debugger, its from Entitas. Thanks to Simon Schmid from Wooga)

  1. Yes for sure you can use it on any device/system! I would recommend to use it. Because of the performance it saves you energie (mobile platform). You can use it even without unity. The unity part is just build on top of it. And yes it works for any version of unity.

  2. Well I dont have a right answer for this right now. I would sugest no. Any typ of array is indeed an reference type in C#. So a workaround could be using hashes of that string. But this will only work if you search the hole string. And we sould not forget… Unity has its own compiler. Maybe they handle things slightly different in memory.

Hi Spy-Shifty. Looks very good. Thanks.

I was looking at Entitas and Svelto recently.

Your approach looks more simple to me then the other two. How production ready would you describe your system?

Well, the software right now is more a beta. I start to test it in live production right now. And I still find some bugs and things to improve. But its more the Unity part of the software. The ecs system it self works till now with no problems.

As soon as I can improve or fix a bug I’ll release a newer version of it. So that you can stay up to date. And I also hope that the community can help me to find bugs and send me feedback to improve the software too.

Later in the day, I will release an update. I added a more easy to use controller for the root system with the ability to add entities of sceneobjects automaticly to the entitymanager. And also fixes for some issues.

On the whole I believe that the software is soon in a state where it is really stable.

There are some features I’ll implement too. For example an entity inspector. A graphic window there you can inspect entities and it’s components (not every entity is a gameobject…).

That’s great.

I will try to play with it also. I’ll let you know if I stumble on anything.

1 Like

New Version is out now!

Fixes:
Inspector issues with ComponentWrapper
Inspector issues with Visual Debugger
Updated Templates
Issues with the ComponentGroup (Components which were created bevor a specific ComponentGroup will now also be added to that group)

I introduce the ECSController class thats the base class for the main controller there you add and execute your systems

using UnityEngine;

namespace ECS {

    // Use this class to control the ECS System
    public class GameController : ECSController<UnityStandardSystemRoot, EntityManager> {

        // Use this for initialization
        protected override void Initialize() {
            AddSystem<MySystem>();

            // or you can use this for more controll over compositions of systems
            //AddSystem(new MySystem());
        }

        // Override this function if you want to controll what Scene Entity should be load in this context
        // The base implementation will add all Scene Entities to the context
        //protected override void AddSceneEntitiesToSystem() {
    
        //}
    }
}

It creates the system and the entity manager by dependency injection for you
With the AddSystem methods you can assign your system to the SystemRoot
The ECSController also executes the Start, Update, and FixedUpdate Routines of the Systems

Thats it for today!
Have fun with it

*************
EDIT
*************
Ah sorry I found one more bug in the visual update system, so that not all the systems wouldn’t called.
It’s now fixed

*************
EDIT
*************

I also forgot to say that I’ve added two Basic Components for Transform and Animator
look at ECSTransform and ECSAnimator

1 Like

I am getting there errors:

Assets/Example/GameObjectExample/ECSTransformComponent.cs(11,18): error CS0101: The namespace ECS' already contains a definition for ECSTransform’

Assets/Example/GameObjectExample/ECSTransformComponent.cs(21,18): error CS0101: The namespace ECS' already contains a definition for ECSTransformComponent’

Fixed I forgot to update the example…

I’ve also added some text to the example scenes

Its ok now.

Some thoughts:

If you want to compete against Entitas and Svelto I would advice to write small and readable examples where the user can get the grip of it.

Svelto made the survival demo but it was really hard to get what is going on.

I have to say, when profiling this is much much slower than entitas and svelto.

I like your code style, but the performance loss is too much to compare it to the others right now :frowning:

Can you go in detail please?

No need , I accidentally opened 3 instances of Unity.

2 Likes

Oh ok :smile:

Wow, dude, that looks promising…
I’ve been working on a lightweight ECS as well, but it’s like half done. Glad you made this and share it to the public.

And when I was implementing ECS in C#, one thing bothers me is that: using array over List, I mean, using List[index] is an indexer, which is a method call, which cause cpu to jmp to another address, that kinda break the DOD’s purpose.

Oh, man, could you put it on the github? or assetstore maybe? That would be easier to follow.

Thank you!
Well, I use an generic array. It’s still in a class but that should be ok. See ComponentArray and ComponentArray. It’s in the ComponentGroup.cs sorry I have to clean it up…

It resize its memory usage by the factor of 2. It only grow at the moment. So I have to change. It’s also not power of 2. I beleve I use a start capacity of 10. I also have to change this.

I’ll do soon

Git goes live! GitHub - Spy-Shifty/BrokenBricksECS: Rebuild of Unity3D upcoming Entity Component System !OUT OF DEVELOPMENT!
I do not have much time for beauty, sorry for that.

I’ll expand it later on

4 Likes