I’ve found that process for creating an entity is unexpectedly difficult.
Practically speaking, the process currently appears to be:
a) Use a MonoBehaviour and spawn a prefab with ConvertToEntity on it.
or, if that isn’t suitable for any number of reasons:
- Create an X : ISharedComponentData object to reference any resources (eg. Mesh, Material, etc).
- Create a Y : IComponentData object to track the existence of required objects.
- Create a Z : SystemBase
In Z, use the WithStructuralChanges().WithoutBurst().Run() special qualifiers to allow entity creation to happen (note, you can also use a command buffer to defer the process, see https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/ECSSamples/Assets/HelloCube/5. SpawnFromEntity/SpawnerSystem_FromEntity.cs, but that’s even more complicated).
In Z’s activity, take a reference X (reference data) and Y (rules), note specifically to use:
(X shared, ref Y rules) => {} in the lambda, because apparently (due to technical limitations according to some obscure forum thread?) shared component data must be listed before component data in the lambda syntax.
You can now run the operation to actually create an entity.
However, if using a prefab to construct the entity, EntityManager.Instantiate will not automatically detect the entity data attached to the prefab. Either manually assign every single instance of ComponentData to the entity instance created, or, as done in the examples (https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/d78b0ff7ad5bb0cac0d3ad18c4c2e9bf114d0c50/ECSSamples/Assets/HelloCube/4. SpawnFromMonoBehaviour/Spawner_FromMonoBehaviour.cs), you must first convert the GameObject prefab into an entity prefab.
var settings = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, null);
var prefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(axisRef.axis.styles.axisEdgePrefab, settings);
entityManager.SetName(prefab, "AxisTemplateEntity");
However, note that in doing so you actually create an entity instance (viewable in the debugger); therefore, the created entity should be cached on your shared component data (X), otherwise you will create two entities every attempt you make to spawn objects.
Finally, entityManager.Instantiate(entityPrefab) will generate a new prefab, and you can use
SetComponentData (note: Not AddComponentData; the entity instance from the prefab will already have the data; use AddComponentData if you manually build the entity from an Archetype).
This matches, it appears, what ConvertToEntity does on a game object.
ie.
- 1 x SharedComponentData for reference data
- 1 x ComponentData for recipe
- 1 x System to spawn
- Convert prefab to entity prefab, cache result
- Generate entities using entityManager.Instantiate(entityPrefab)
- Update the recipe with a reference ID so you don’t just endlessly spawn entities
- Do not forget correct invokation (WithStructuralChanges, etc).
So, anyway, this feels rather unexpectedly difficult and painful for what should be a trivial operation.
I had a good look at the examples too, and well, that seems to be how you do it.
(and heck, maybe this is even wrong, since the examples use
IDeclareReferencedPrefabs, IConvertGameObjectToEntity to convert the prefab into an entity prefab, even though its done as per the code snippet above in other places in the same project…?)
I guess, am I missing something?
Is there a helper library somewhere that people use for this stuff?