Pure ECS is lacking lots of system to make real games right now
and probably it’ll take not one year to rewrite all existent systems to use pure data oriented approach
But hybrid approach based on GameObjectEntity looks a bit wired for me.
Having a MonoBechaviour attached to entity brings few problems:
It violates principles of data oriented design - components are objects that contain logic
It makes serialisation/deserealisation of an entity to be a complicated thing
you’ll need to make a huge refactoring when pure systems arrive
you can’t use Jobs
Also i think that hybrid mode should
create game objects for each entity,
not entity for each game object
Why not to go a wrapper way?
It is possible to create systems that operate on pure DataComonents but inside use GameObjects to do their job. And if data-api be the same, you’ll be able simply to switch to pure system when it’ll arrive.
For sure this wrapped system going to be slow, because it’ll need to copy data each frame ecs>oop>ecs.
But it’ll allow to start developing in data oriented way.
I’ve made a test project that wraps physics and mouse events, and it works totally fine for me.
i have few systems there:
BoxEmitterSystem - creates entities with a small delay with randomized position
those entities have 4 components: prefab(contains an id of prefab), position(float3), rotation(float3), clickable(empty)
GameObjecManagerSystem - creates/removes GameObjects for each Entity with prefab component and maintain a dictionary that maps entity-to-gameobject
GameObjectTrasformationSystem - keeps Entity position and rotation synchronized to GameObject (actually 2 systems there: one to read game object data, and second to write it) it is possible to synchronize any MonoBehavior property to pure ecs component this way
GameObjectClickSystem - creates event-entity with click-target-entity after clicking on GameObject
ClickEventsHandlerSystem - consumes events and removes entities that was clicked
(I can share it if someone interested)
as a result I have working physics, and only pure data
I did this in the same way. Writing some systems that will synchronize my data with the real world.
But I skipped it because it cause me some problems and the trade off wasn’t that big. Instead I had to write synch systems for different mono components…
If you want to use Jobs or you have some other problems with the hybrid mode, you can do it this way.
I went back to hybrid.
(I’m currently prototyping)
My question was mostly to unity development team, is it reasonable for unity to go this way as well?
yes I’m thinking now about “generic synchronizer” that be able to synch any property of any mono component to custom IComponentData on corresponding entity
One thing that I find particularly annoying when using the hybrid approach is to deal with instantiating prefabs that have components attached to it (using a component wrapper).
Indeed, there is nothing equivalent to PostUpdateCommand.CreateEntity() for GameObjects.
Thus I have been forced several times to write “spawn systems” that only do something like :
[Inject] private SomeGroup group;
protected override void OnUpdate()
{
List<SomeSpawnData> toSpawn = new List<SomeSpawnData>();
for (int i = 0; i < group.Length; i++)
{
toSpawn.Add(new SomeSpawnData {
//spawn info here
});
PostUpdateCommands.DestroyEntity(group.Entities[i]);
}
foreach (SomeSpawnData data in toSpawn)
{
//instantiate game object here and use spawn data to set entity components
}
}
This makes it sadly impracticable and forces us to have a big “SomeSpawnData” structure that contains all the possible things we want to do when spawning an entity (for instance adding other components in some specific cases, etc.)
I just tried it, you have to attach “HybridWorld” and “PrefabsList” to the GameSettings. In the prefab list, set its size to 1 and add the box prefab (you might need to also add a material to the prefab).
On the box prefab, attach the script “MouseEventGenerator” and here you go
Also, you have to remove some namespace in one of the script file. Somethinf like PureECS.something if I remember right
This approach is quite nice but its missing one big thing imho. GameObject to entity allows complex prefabs to be spawned in one go ( think of hierarchical prefabs with ECS entities and components on all/ some children ). This is easily achievable with only very little boilerplate.
You can still do this here as well, but the workflow is anything but natural as you’d have to link a prefab manually for each child then also handle parenting, etc.
complex object structures is absolutely unrelated to problem i’m talking about - purity of hybrid mode
When switching from OOP to ECS - you have to start thinking differently,
it is hard to forget a habit of thinking by objects
close Hierarchy inspector and look only on Entity Debugger, all is data now
if you need any data structure other than list - tree, or graph, or grid, simply introduce a new entity or component representing a link between nodes.
Unfortunateley unity don’t have a runtime load format for entities:
the only way to construct a pure-data-entity is programmatically using EntityManager API, there is no gui tool for it right now
there is no way to save current entity state, even if it contains only pure IComponentData structs there is no good way to serialize all it’s components
there is no thing like SerializedEntity - you can’t tweak entity properties in inspector
Oop and prefabs with hierarchies for the sake of workflow have nothing in common. It is mostly unrelated to one’s chosen programming paradigm.
Not sure if you’ve shipped games with both prefab and template ( flat archetype ) based workflows. We have, and templates are a nightmare, for everyone involved. Particularly designers and artists, but not only.
Even with pure ecs you can keep your data in prefabs before creating entities ( flat or otherwise ) and this is what you lose with this system. If it helps, think of automating linkage and all the manual labour that comes with it.
sure game object is a convenient thing, i’m not saying anything about it, but GameObjectEntity puts MonoBechaviour Objects to Entities, i’m complaining only about it
I see that your approach requires to use a lot of GetComponent<> calls on GameObjects, for instance to update its Transform from your Position component.
Isn’t that specifically slow ?
What do you think about instead passing the EntityManager and Entity to a MonoBehaviour and having it call EntityManager.GetComponentData(Entity) to update it Transform ?
Do you know which one is faster between EntityManager.GetComponentData and Object.GetComponent ?
This does not seem to be compatible with the approach proposed here (see first post). Or maybe I misunderstood what you meant ?
To complete : let’s suppose you want to instantiate a new Entity. Currently there is no way to do this in PostUpdateCommands using a GameObject with the GameObjectEntity on it (you can only call the usual Instantiate function which breaks the injected data if there are components attached to it). So the idea is that instead you only work with pure ECS and make a “bridge” with unity game object using a dictionnary that maps entity to gameobject, and instiate/destroy prefabs as needed