Basic integration to UnityEditor for Entity Component System

ECS framework works good enough, but it’s non-visual thing and works as background code. What if we want to get some visualization about data inside?

ECS framework works good enough, but it’s non-visual thing and works as background code. What if we want to get some visualization about data inside?

There is extension for fix it - UnityEditor integration. It allows to visualize ecs world entities and components on them as it works for standard unity game objects and monobehaviours.

Test environment

Let’s create test environment. It will be default scene with new GameObject (name can be any, i used “_LOGIC”) and MonoBehaviour component on it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
sealed class UnityIntegrationTest : MonoBehaviour {
EcsWorld _world;

EcsSystems _systems;

void OnEnable () {
_world = new EcsWorld ();
#if UNITY_EDITOR
// observer should be created before any entity will be created.
UnityIntegration.EcsWorldObserver.Create (_world);
#endif
_systems = new EcsSystems (_world).Add (new TestSystem ());
_systems.Initialize ();
#if UNITY_EDITOR
UnityIntegration.EcsSystemsObserver.Create (_systems);
#endif
}

void Update () {
_systems.RunUpdate ();
}

void OnDisable () {
_systems.Destroy ();
}
}

UnityEditor integration was processed with two lines:

1
2
3
UnityIntegration.EcsWorldObserver.Create (_world);
...
UnityIntegration.EcsSystemsObserver.Create (_systems);

Both should be wrapped to #if UNITY_EDITOR preprocessor define, otherwise project will not work as standalone application (editor only).

Rest part of ECS (components and system):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
class UnityIntegrationComponent1 {
public Vector3 Position;

public Transform CameraTransform;
}

class UnityIntegrationComponent2 {
public int Id;

public string Name;

public float Time;
}

sealed class TestSystem : IEcsInitSystem, IEcsRunSystem {
[EcsWorld]
EcsWorld _world;

[EcsFilterInclude (typeof (UnityIntegrationComponent2))]
EcsFilter _filter;

void IEcsInitSystem.Initialize () {
var entity = _world.CreateEntity ();
var c1 = _world.AddComponent<UnityIntegrationComponent1> (entity);
c1.Position = new Vector3 (1f, 2f, 3f);
c1.CameraTransform = Camera.main.transform;

var c2 = _world.AddComponent<UnityIntegrationComponent2> (entity);
c2.Id = 456;
c2.Name = "Tester";
}

void IEcsInitSystem.Destroy () { }

EcsRunSystemType IEcsRunSystem.GetRunSystemType () {
return EcsRunSystemType.Update;
}

void IEcsRunSystem.Run () {
// test creating and removing entites in loop.
var entity = _world.CreateEntity ();
_world.AddComponent<UnityIntegrationComponent1> (entity);
_world.RemoveEntity (entity);

// change component field in loop.
foreach (var c2entity in _filter.Entities) {
_world.GetComponent<UnityIntegrationComponent2> (c2entity).Time = Time.time;
}
}
}

At TestSystem initialization one entity was created with UnityIntegrationComponent1 and UnityIntegrationComponent2 components on it. At Run-loop you can see how new entity with UnityIntegrationComponent1 will be created and destroyed - it was added for testing entity / component pooling.

Visualization

After start editor scene should looks like this:

You can see that new [ECS-WORLD] game object was created and it contains representation of created (enabled game objects) and removed entities (disabled game objects).

At ecs-world representation you can find some information about data inside:

At ecs-entity representation you can find list of attached ecs-components with values of their fields:

At ecs-systems representation you can find list of attached ecs-systems:

As additional feature, you can temporary disabled execution of run-systems with changing flag "Run systems activated".

All representation data - readonly by design, it can’t be changed from unity editor (one side data-binding). Maybe later additional options as “AddComponent” and “RemoveComponent” will be added here, but ecs-data can’t be edited from unity editor in any way.

At TestSystem you can find that UnityIntegrationComponent2.Time field will be updated each frame but at inspector you can see static number. Its how unity editor works by default - inspector will be repainted only on some event: clicking, dragging, resizing, etc. So, if you need actual value right now, you can just click somewhere inside inspector panel. This behaviour can be changed later, but I’m not sure that performance / GC penalties worth it.