Search Unity

Trying to spawn units using ECS

Discussion in 'Entity Component System' started by stefan-falk, Dec 27, 2019.

  1. stefan-falk

    stefan-falk

    Joined:
    Nov 24, 2019
    Posts:
    15
    Hi!

    I am following this talk
    and try to understand how to spawn units as I click my mouse (for testing purposes).

    For this in general, I created a UnitBase etc. which implements IConvertGameObjectToEntity::Convert to make sure all units can be converted to a Entity objects and looks like this:

    Code (CSharp):
    1.  
    2. namespace Units
    3. {
    4.     public abstract class UnitBase : MonoBehaviour, IConvertGameObjectToEntity
    5.     {
    6.         public float health;
    7.  
    8.         public bool selected;
    9.  
    10.         public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    11.         {
    12.             dstManager.AddComponentData(entity, new Translation {Value = transform.position});
    13.             dstManager.AddComponentData(entity, new Rotation {Value = transform.rotation});
    14.             dstManager.AddComponentData(entity, new Selected {Value = selected});
    15.             dstManager.AddComponentData(entity, new Health {Value = health});
    16.         }
    17.     }
    18.  
    19.     public abstract class MobileUnitBase : UnitBase
    20.     {
    21.         public float speed;
    22.  
    23.         public new void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    24.         {
    25.             base.Convert(entity, dstManager, conversionSystem);
    26.             dstManager.AddComponentData(entity, new Speed {Value = speed});
    27.         }
    28.     }
    29. }
    30.  
    These are the main components:

    Code (CSharp):
    1.  
    2. namespace ECS.Components
    3. {
    4.     public class Health : IComponentData
    5.     {
    6.         public float Value;
    7.     }
    8.    
    9.     public class Speed : IComponentData
    10.     {
    11.         public float Value;
    12.     }
    13.    
    14.     public class Selected : IComponentData
    15.     {
    16.         public bool Value;
    17.     }
    18. }
    19.  
    Now, in my Test script I have this:


    Code (CSharp):
    1. public class Test : MonoBehaviour
    2. {
    3.     public GameObject unitPrefab;
    4.  
    5.     private EntityManager _entityManager;
    6.     private Entity _unitEntityPrefab;
    7.  
    8.     // Start is called before the first frame update
    9.     void Start()
    10.     {
    11.         _entityManager = World.DefaultGameObjectInjectionWorld.EntityManager;
    12.         _unitEntityPrefab  = GameObjectConversionUtility.ConvertGameObjectHierarchy(unitPrefab, World.Active);
    13.     }
    14.  
    15.     // Update is called once per frame
    16.     void Update()
    17.     {
    18.         if (Input.GetMouseButtonDown(0))
    19.         {
    20.             SpawnUnit(15, 15);
    21.         }
    22.     }
    23.  
    24.     private void SpawnUnit(float x, float z)
    25.     {
    26.         Debug.Log($"Spawning unit at  x:{x} y:{z}");
    27.         var unitEntity = this._entityManager.Instantiate(this._unitEntityPrefab);
    28.         _entityManager.SetComponentData(unitEntity, new Translation {Value = new Vector3(x, 1, z)});
    29.         _entityManager.SetComponentData(unitEntity, new Rotation {Value = Quaternion.Euler(0, 0, 0)});
    30.         _entityManager.SetComponentData(unitEntity, new Health {Value = 100f});
    31.         _entityManager.SetComponentData(unitEntity, new Selected {Value = false});
    32.     }
    33. }
    Where unitPrefab is just a simple GameObject that has a Capsule on it and a, basically empty, script which is empty for now:

    Code (CSharp):
    1.  
    2. public class UnitScript : UnitBase
    3. {
    4.     // Start is called before the first frame update
    5.     void Start()
    6.     {
    7.  
    8.     }
    9.  
    10.     // Update is called once per frame
    11.     void Update()
    12.     {
    13.  
    14.     }
    15. }
    16.  
    The thing is, as I click, the entities get created but the unit is not rendered.

    Obviously I am missing something but I don't see what it is.

    Any help would be much appreciated!
     
    Last edited: Dec 27, 2019
  2. Eldirfar

    Eldirfar

    Joined:
    Feb 9, 2014
    Posts:
    65
    To render someting you need RenderMesh Component. Make sure you have it after conversion. MeshRenderer should be automatically converted to it. Maybe you are missing Hybrid Renderer Package.

    BTW all IComponentData should be structs not classes :)
     
  3. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,685
    They can be both. From 0.4.0 added class IComponentData for storing non jobified managed data without chunk splitting like in ISCD.
     
  4. vildauget

    vildauget

    Joined:
    Mar 10, 2014
    Posts:
    121
    Recommend reading docs before anyone uses class IComponentData, as it's "To help porting existing code over to ECS in a piecemeal fashion", and "internally are handled in a much different (and slower) way".

    For OP I support Eldirfar's suggestions, check that entities has RenderMesh and LocalToWorld Components in the Entity Debugger, and make sure Hybrid Renderer Package is added to project. EDIT: Also check that the prefab has a material.