Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

How to optimally combine entity Instantiate with Archetype?

Discussion in 'Entity Component System' started by Antypodish, Aug 8, 2019.

  1. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,753
    As per 2018.x, I used archetype to create new entities. Then I loaded prefab mesh via SharedComponent.
    With 2019.x changes, I understand that Instantiate is recommended way, to create one or more entities, based on prefabs. However, I don't see option, to best way combine instantiation of prefab with archetype. Any good options for that?

    So far 2 way I can think of.
    • Either instantiate prefab from entity and add desired components. Which I don't think is most optimal way, to generate thousands of entities.
    Or
    • Generate desired entities with archetype, then set mesh via SharedComponent, from entity prefab.
    Any thoughts?
     
    florianhanke likes this.
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    For the majority of entity creation I think the best way is to use conversion system.

    Create your prefab as a game object.
    Convert it to an entity.
    Add Prefab component.

    Pass entity to jobs if you need an instantiate using that.

    Outside of pure data entities (only exist to hold data, no renderer etc), I don't see much point in instantiating an Entity with an archetype anymore. Using Unitys existing systems, custom editor extensions etc is much easier.
     
  3. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,753
    Yep, I use Convert and I generate prefab entities.
    So I think these points I got covered:
    I am able to spawn these instantiated prefab entities. So thats is fine.

    However, I am not sure if I understood correctly following part
    Do you mean:
    1. I populate my generated prefab entity, with same components as archetype.
    2. Then instantiate from that prefab.
    If so, that appears to be good solution.
     
  4. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    There's literally a component called Prefab
    You can add to entities so that the entity won't show up in a system

    Code (CSharp):
    1.     /// <summary>
    2.     /// Marks the entity as a prefab, which implicitly disables the entity.
    3.     /// </summary>
    4.     /// <remarks> By default, an <see cref="EntityQuery"/> ignores all entities that have a Prefab component. You
    5.     /// can override this default behavior by setting the <see cref="EntityQueryOptions.IncludePrefab"/> flag of the
    6.     /// <see cref="EntityQueryDesc"/> object used to create the query. When using the EntityQueryBuilder class
    7.     /// in a ComponentSystem, set this flag by calling the <see cref="EntityQueryBuilder.With(EntityQueryOptions)"/>
    8.     /// function.</remarks>
    9.     public struct Prefab : IComponentData
    10.     {
    11.     }
    This way you can generate a bunch of Entities that act as Prefabs and Instantiate off them.
    This way you only need to convert it once and can pass it to jobs.
     
    Last edited: Aug 8, 2019
    florianhanke, Grizmu and Antypodish like this.
  5. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    529
    Comparison between create with archetype and instantiate:

    With Archetype:
    Code (CSharp):
    1. var archetype = EntityManager.CreateArchetype(typeof(SharedComponent1), typeof(Component2), typeof(Component3));
    2. var entities = new NativeArray<Entity>(1000, Allocator.Temp);
    3. EntityManager.CreateEntity(archetype, entities);
    4. for (var i = 0; i < entities.Length; i++)
    5.     EntityManager.SetSharedComponentData(entities[i], new SharedComponent1 {Value = 123});
    With Instantiate:
    Code (CSharp):
    1. var prefab = EntityManager.CreateEntity(typeof(Prefab), typeof(SharedComponent1), typeof(Component2), typeof(Component3));
    2. EntityManager.SetSharedComponentData(prefab, new SharedComponent1{Value = 123});
    3. var entities = new NativeArray<Entity>(1000, Allocator.Temp);
    4. EntityManager.Instantiate(prefab, entities);
    You can prevent additional structural changes by setting shared components on the prefab and initialize any other component data on it. Additionally Instantiate is able to create full entity hierarchies when LinkedEntityGroup is present on the prefab.
    BTW: Prefab component is not required, you can use Instantiate to clone existing active objects too.
     
    florianhanke and Antypodish like this.
  6. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,753
    @tertle
    Ah right. I have seen that before somewhere, while reading. Haven't used it as of yet.

    Edit:
    @julian-moschuering that very insightful. It gives me some extra thoughts.

    Thanks guys.
     
    Last edited: Aug 8, 2019
  7. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,753
    Also something to add that might be useful for you if you didn't realize.

     
  8. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,753
    This is something definitely new to me.
    Looks that it may be quite useful.
     
  9. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,753
    Just to let you know, I got things working yesterday.
    I used guidelines from you both. Thx.

    One thing I haven't implemented yet, Is what @tertle suggested in last post, since I can have potentially mix of different meshes instantiating, under same query. So I don't think I can effectively utilize this method at this point, in my current project / state.

    One of solutions would be, having entities sorted by mesh type. Then I could run groups query EntityManager.SetSharedComponentData(EntityQuery query, T componentData).

    But I am not sure, if is feasible in my case, as Entities instantiation order is more important, than mesh type.
    At least at this point.
     
  10. julian-moschuering

    julian-moschuering

    Joined:
    Apr 15, 2014
    Posts:
    529
    You can probably change the SCD Filter on EntityQuery.

    What I did alot is :
    * collecting all data to create new instances
    * sort that array eg by Mesh
    * run over array,
    ** get start/end with same mesh
    ** change prefab to reflect the current 'batch'
    ** instantiate
     
    Antypodish likes this.
  11. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,753
    This sounds sensible.

    I suppose, now only way to really decide on best approach, is to benchmark proposed filtering/sorting method vs iterating and setting directly without filtering, for my specific case scenario.