Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Finding specific entity data by ComponentData

Discussion in 'Entity Component System' started by colin_young, Nov 21, 2019.

  1. colin_young

    colin_young

    Joined:
    Jun 1, 2017
    Posts:
    243
    I've got a bunch of entities with associated data (IComponentData and IBufferElementData) hanging out in memory. Technically it's a graph of connected lanes for a road system, or would be if I could figure out how to get at them. I've got another set of entities, vehicles, which have data associated with them:
    • Lane: LaneIdentityComponent, LanePointsComponent, LaneExitIdentityComponent, other lane data
    • Vehicle: LaneIdentityComponent, CurrentLanePointsComponent, NeedsNewLaneTag, other vehicle data
    I have a job that operates on the vehicles (identified by a tag), and I'd like to be able to find the matching LanePointsComponent on the matching Lane, identified by the LaneIdentityComponent. What I'd like to be able to do is copy the data from LanePointsComponent into a component on the vehicle. Given there are about 800-900 lanes in memory, what is the best way to go about finding the correct lane to get data from? I envision a system that would operate on all entities with NeedsNewLaneTag, find the correct LaneExitIdentityComponent and copy that data into the CurrentLanePointsComponent and remove the NeedsNewLaneTag.

    Does this seem like a reasonable approach? And how do I get the data out of my lane entities that are just kind of hanging around in memory at the moment?
     
  2. kingstone426

    kingstone426

    Joined:
    Jun 21, 2013
    Posts:
    43
    It would be easier if vehicles cold hold a direct reference to their lane's entity, something like this: (not tested)
    Code (csharp):
    1.  
    2. [RequireComponentTag(typeof(NeedsNewLaneTag))]
    3. struct LaneJob : IJobForEachWithEntity<LaneIdentityComponent>
    4. {
    5.     [NativeDisableParallelForRestriction] public ComponentDataFromEntity<LanePointsComponent> lanePoints;
    6.  
    7.     public EntityCommandBuffer.Concurrent commandBuffer;
    8.  
    9.     public void Execute(Entity entity, int i, [ReadOnly] ref LaneIdentityComponent laneIdentity)
    10.     {
    11.         var points = lanePoints[entity];
    12.         points.data = lanePoints[laneIdentity.entity].data;
    13.         lanePoints[entity] = points;
    14.        
    15.         commandBuffer.RemoveComponent<NeedsNewLaneTag>(i, entity);
    16.     }
    17. }
    18.  
    But perhaps that is not possible in your situation? If not, I guess you could use a NativeHashMap as LaneIdentity -> Entity lookup.
     
  3. colin_young

    colin_young

    Joined:
    Jun 1, 2017
    Posts:
    243
    That gives me some ideas. Thanks!

    There is one thing I'm not sure about. I actually need to get the LanePointsComponent for the entity that has a LaneIdentityComponent that is equal to the LaneExitIdentityComponent of the lane that has the LaneIdentityComponent equal to the current LaneIdentityComponent on the vehicle. Pseudo-code:

    points = lanes WHERE lane.identity = vehicle.currentLane.laneExitIdentity

    Your NativeHashMap suggestion might be the way to go. The graph is read-only so I should be able to construct that in the OnCreate for the job.
     
  4. Vacummus

    Vacummus

    Joined:
    Dec 18, 2013
    Posts:
    191
    I think that is a good way to do it if you are happy with the performance of that approach (there is much more performant ways to do it, but it would be complicating and challenging to implement).

    As for the second question, I would create a CurrentLane component that exists on the vehicle entities which would hold an entity ref to its current lane entity.

    Code (CSharp):
    1. public struct CurrentLane: IComponentData
    2. {
    3.     public Entity laneEntity;
    4. }
    Then you can use that entity to get its LanePointsComponent by using ComponentDataFromEntity<LanePointsComponent>.
     
  5. colin_young

    colin_young

    Joined:
    Jun 1, 2017
    Posts:
    243
    Thanks. The entity reference is a good idea. I don't know why I didn't think of it, but I suspect it may not have occurred to me that you could store an entity reference like that.

    I've also realized that I'm storing my points as DynamicBuffers, and I think I might need to convert those to NativeArray or something, but that's a separate issue.
     
  6. Vacummus

    Vacummus

    Joined:
    Dec 18, 2013
    Posts:
    191
    Glad that was helpful.

    I don't have much experience when it comes NativeArrays, but my understanding is that they can't be used inside of IComponentData, and that DynamicBuffers were created to solve the problem of being able to work with arrays within the ECS framework (able to tightly back arrays with other components and query them like any other components). I might be wrong here? But if you were to use NativeArrays instead of DynamicBuffers for storying your points, what would that look like?
     
  7. Reloque

    Reloque

    Joined:
    Apr 28, 2015
    Posts:
    207
    I have a similar use case, I have a mining ship that has a target. That target is an entity and I need, to mine the target, have a reference to it. I am going to try your solution. Tx.
     
  8. colin_young

    colin_young

    Joined:
    Jun 1, 2017
    Posts:
    243
    Yeah, after re-reading the docs on DynamicBuffer, it seems their purpose is to replace arrays :) So I accidentally did the right thing.