Search Unity

Reference a child on ECS

Discussion in 'Entity Component System' started by DaniParra, Apr 16, 2019.

  1. DaniParra

    DaniParra

    Joined:
    Apr 27, 2014
    Posts:
    29
    Hi all,

    I've some doubts about how to reference the Transform of a child in ECS.

    I've a Prefab representing a cannon, the cannon has a point where I want to instantiate the bullet. The problem is that I don't know how to transfer this point to the system in order to create the bullet at this point.

    Cannon.png
    CannonInspector.png

    This is the conversion code for GameObject to Entity, I was storing the instance point in SpawnInfo, the problem is that if the cannon moves, this point is not updated (this is not a reference). How can I solve that? Should I create another entity for the gun and relate the two entities in order to ask for the position?

    Code (CSharp):
    1.  
    2. [RequiresEntityConversion]
    3.     public class CannonProxy : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity
    4.     {
    5.         [SerializeField] private float _fireRate;
    6.         [SerializeField] private Transform _spawnPoint;
    7.         [SerializeField] private GameObject _bulletPrefab;
    8.  
    9.         public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    10.         {
    11.             dstManager.AddComponentData(entity, new Cannon());
    12.             dstManager.AddComponentData(entity, new Gun {FireRate = _fireRate});
    13.             dstManager.AddComponentData(entity, new SpawnInfo
    14.             {
    15.                 Prefab = conversionSystem.GetPrimaryEntity(_bulletPrefab),
    16.                 Position = _spawnPoint.position,
    17.                 Rotation = _spawnPoint.rotation
    18.             });
    19.         }
    20.  
    21.         public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
    22.         {
    23.             Assert.IsNotNull(_bulletPrefab);
    24.             referencedPrefabs.Add(_bulletPrefab);
    25.         }
    26.     }
    Thank you.
     
  2. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    On that scenario you will have to pass the _spawnPoint using the prefab workflow. i.e Add the _spawnPoint gameobject reference entity and then store it in you SpawnInfo component data.
    Then your SpawnBullets system will use the spawnPoint entity to gather the position where the bullet prefab will be spawned.
    Code (CSharp):
    1. [RequiresEntityConversion]
    2. public class CannonProxy : MonoBehaviour, IDeclareReferencedPrefabs, IConvertGameObjectToEntity {
    3.   [SerializeField] private float _fireRate;
    4.   [SerializeField] private Transform _spawnPoint;
    5.   [SerializeField] private GameObject _bulletPrefab;
    6.  
    7.   public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem) {
    8.     dstManager.AddComponentData(entity, new Cannon());
    9.     dstManager.AddComponentData(entity, new Gun { FireRate = _fireRate });
    10.     dstManager.AddComponentData(entity, new SpawnInfo {
    11.       Prefab = conversionSystem.GetPrimaryEntity(_bulletPrefab),
    12.       SpawnEntity = conversionSystem.GetPrimaryEntity(_spawnPoint.gameObject)
    13.     });
    14.   }
    15.  
    16.   public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs) {
    17.     Assert.IsNotNull(_bulletPrefab);
    18.     referencedPrefabs.Add(_bulletPrefab);
    19.     Assert.IsNotNull(_spawnPoint);
    20.     referencedPrefabs.Add(_spawnPoint.gameObject);
    21.   }
    22. }
     
    lndcobra likes this.
  3. DaniParra

    DaniParra

    Joined:
    Apr 27, 2014
    Posts:
    29
    Hi!

    The conversion works perfectly, thanks!. But I'm not sure about how to get a ComponentData from an Entity on a JobComponentSystem.

    Code (CSharp):
    1. public class TryFireSystem : JobComponentSystem
    2.     {
    3.         private EndSimulationEntityCommandBufferSystem _commandBufferSystem;
    4.         private EntityArchetype _spawnerArchetype;
    5.  
    6.         protected override void OnCreate()
    7.         {
    8.             _commandBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    9.             _spawnerArchetype = EntityManager.CreateArchetype(typeof(Spawner), typeof(SpawnInfo));
    10.         }
    11.  
    12.         [RequireComponentTag(typeof(TryFire))]
    13.         struct TryFireJob : IJobForEachWithEntity<Gun, SpawnInfo>
    14.         {
    15.             public EntityCommandBuffer CommandBuffer;
    16.             public EntityArchetype SpawnerArchetype;
    17.             public float CurrentTime;
    18.  
    19.             public void Execute(
    20.                 Entity entity,
    21.                 int index,
    22.                 ref Gun gun,
    23.                 [ReadOnly] ref SpawnInfo spawnInfo)
    24.             {
    25.                 CommandBuffer.RemoveComponent<TryFire>(entity);
    26.  
    27.               ...
    28.  
    29.                 var spawnPosition = XXX.GetComponentData<Translation>(gun.SpawnPoint).Value;
    30.                
    31.  
    32.                 ...
    33.             }
    34.         }
    35.  
    36.         protected override JobHandle OnUpdate(JobHandle inputDependencies)
    37.         {
    38.             var job = new TryFireJob()
    39.             {
    40.                 CommandBuffer = _commandBufferSystem.CreateCommandBuffer(),
    41.                 SpawnerArchetype = _spawnerArchetype,
    42.                 CurrentTime = Time.time
    43.             }.ScheduleSingle(this, inputDependencies);
    44.  
    45.             _commandBufferSystem.AddJobHandleForProducer(job);
    46.  
    47.             return job;
    48.         }
    I've tried to pass the EntityManager to the Job, but this is a class.
     
  4. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    You can't access EntityManager inside a job.
    Pass ComponentDataFromEntity<LocalToWorld> to the job then access the Position property and assign it to the Translation of your spawned object.

    Also look at this example for spawning a prefab.
     
  5. DaniParra

    DaniParra

    Joined:
    Apr 27, 2014
    Posts:
    29
    This works, but is it optimal? With GetComponentDataFromEntity<LocalToWorld> am I asking for all the LocalToWorld components?
     
  6. GilCat

    GilCat

    Joined:
    Sep 21, 2013
    Posts:
    676
    That is very performant and the correct way of accessing components from other entities.
     
    eterlan likes this.
  7. DaniParra

    DaniParra

    Joined:
    Apr 27, 2014
    Posts:
    29
    Perfect, thank you very much for your help :D
     
  8. unity_AB16870EE17921501CEE

    unity_AB16870EE17921501CEE

    Joined:
    Apr 2, 2021
    Posts:
    3
    When I make entity as child of other entity than collider of child entity is not working.