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. Dismiss Notice

Question How do you change component data within ITriggerEventsJob?

Discussion in 'Entity Component System' started by voidraizer, Mar 9, 2021.

  1. voidraizer

    voidraizer

    Joined:
    Dec 20, 2013
    Posts:
    6
    Hello, I'm just starting my dive into DOTS and am about 6 days deep. I've made it to the point where I understand most of the ECS concepts (I think), but am still rather fuzzy on the Jobs and Burst pillars. To get started, I completed most of the tutorials I could find and have started to try to do something on my own.

    I followed this Pong tutorial and decided to try to handle the collisions programmatically like how I'd do it in OOP. I've made it to the point where my triggers are actually working (specifically the goal triggers on the far sides of the paddles), thanks to this helpful physics tutorial.

    I'm able to detect a trigger event, identify the entities involved and despawn my ball. The issue I've run into is, I cannot trigger my new ball to be spawned and record the point scored for the player. Below is my current GoalSystem code and I'm sure it's horrendous so brace yourselves:

    Code (CSharp):
    1. using UnityEngine;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4. using Unity.Physics;
    5. using Unity.Physics.Systems;
    6. using Unity.Collections;
    7.  
    8. [AlwaysSynchronizeSystem]
    9. public class GoalSystem : JobComponentSystem
    10. {
    11.     private BuildPhysicsWorld buildPhysicsWorld;
    12.     private StepPhysicsWorld stepPhysicsWorld;
    13.     private EndSimulationEntityCommandBufferSystem ecBufferSystem;
    14.     // private EntityQuery spawnDataGroup;
    15.     // private EntityQuery textDataGroup;
    16.  
    17.     private struct TriggerJob : ITriggerEventsJob
    18.     {
    19.         public ComponentDataFromEntity<BallTag> ballTag;
    20.         public ComponentDataFromEntity<WallTag> wallTag;
    21.         public ComponentDataFromEntity<PaddleTag> paddleTag;
    22.         public ComponentDataFromEntity<LeftGoalTag> leftGoalTag;
    23.         public ComponentDataFromEntity<RightGoalTag> rightGoalTag;
    24.         // public Entity spawnEntity;
    25.         // public Entity textEntity;
    26.         // public ComponentDataFromEntity<SpawnComponent> spawnDataFromEntity;
    27.         // public ComponentDataFromEntity<TextChangeComponent> textDataFromEntity;
    28.         public EntityCommandBuffer.ParallelWriter ecb;
    29.  
    30.         public void Execute( TriggerEvent evt )
    31.         {
    32.             // SpawnComponent spawnData = spawnDataFromEntity[spawnEntity];
    33.             // TextChangeComponent textData = textDataFromEntity[textEntity];
    34.  
    35.             if( ballTag.HasComponent( evt.EntityA ) && ( leftGoalTag.HasComponent( evt.EntityB ) ) )
    36.             {
    37.                 Debug.Log( "1" );
    38.                 // textData.p2Score++;
    39.                 ecb.DestroyEntity( 1, evt.EntityA );
    40.                 // spawnData.doSpawn = true;
    41.             }
    42.             else if( ballTag.HasComponent( evt.EntityB ) && ( leftGoalTag.HasComponent( evt.EntityA ) ) )
    43.             {
    44.                 Debug.Log( "2" );
    45.                 // textData.p2Score++;
    46.                 ecb.DestroyEntity( 1, evt.EntityA );
    47.                 // spawnData.doSpawn = true;
    48.             }
    49.             else if( ballTag.HasComponent( evt.EntityA ) && ( rightGoalTag.HasComponent( evt.EntityB ) ) )
    50.             {
    51.                 Debug.Log( "3" );
    52.                 // textData.p1Score++;
    53.                 ecb.DestroyEntity( 1, evt.EntityA );
    54.                 // spawnData.doSpawn = true;
    55.             }
    56.             else if( ballTag.HasComponent( evt.EntityB ) && ( rightGoalTag.HasComponent( evt.EntityA ) ) )
    57.             {
    58.                 Debug.Log( "4" );
    59.                 // textData.p1Score++;
    60.                 ecb.DestroyEntity( 1, evt.EntityA );
    61.                 // spawnData.doSpawn = true;
    62.             }
    63.         }
    64.     }
    65.  
    66.     protected override void OnCreate()
    67.     {
    68.         base.OnCreate();
    69.  
    70.         buildPhysicsWorld = World.GetOrCreateSystem<BuildPhysicsWorld>();
    71.         stepPhysicsWorld = World.GetOrCreateSystem<StepPhysicsWorld>();
    72.         ecBufferSystem = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    73.         // spawnDataGroup = GetEntityQuery( typeof( SpawnComponent ) );
    74.         // textDataGroup = GetEntityQuery( typeof( TextChangeComponent ) );
    75.     }
    76.  
    77.     protected override JobHandle OnUpdate( JobHandle inputDeps )
    78.     {
    79.         // NativeArray<Entity> s = spawnDataGroup.ToEntityArray( Allocator.TempJob );
    80.         // NativeArray<Entity> t = textDataGroup.ToEntityArray( Allocator.TempJob );
    81.  
    82.         TriggerJob triggerJob = new TriggerJob()
    83.         {
    84.             ballTag = GetComponentDataFromEntity<BallTag>(),
    85.             wallTag = GetComponentDataFromEntity<WallTag>(),
    86.             paddleTag = GetComponentDataFromEntity<PaddleTag>(),
    87.             leftGoalTag = GetComponentDataFromEntity<LeftGoalTag>(),
    88.             rightGoalTag = GetComponentDataFromEntity<RightGoalTag>(),
    89.             // spawnEntity = s[0],
    90.             // textEntity = t[0],
    91.             // spawnDataFromEntity = GetComponentDataFromEntity<SpawnComponent>(),
    92.             // textDataFromEntity = GetComponentDataFromEntity<TextChangeComponent>(),
    93.             ecb = ecBufferSystem.CreateCommandBuffer().AsParallelWriter()
    94.         };
    95.  
    96.         // s.Dispose();
    97.         // t.Dispose();
    98.  
    99.         return triggerJob.Schedule( stepPhysicsWorld.Simulation, ref buildPhysicsWorld.PhysicsWorld, inputDeps );
    100.     }
    101. }
    102.  
    I've commented out all the code for how I was getting the entities with the spawn and text components as it did work and I could successfully read my textData.p1Score and the current state of spawnData.doSpawn, etc.. but I writing to it didn't actually change any data on the corresponding entities.

    I'm sure there's a better way to do this, so please highlight all my flaws.
     
  2. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    The problem you're having is when you're working with components your data is a struct.
    If you make changes like this,

    textData.p2Score++;
    spawnData.doSpawn = true;

    You're only making local changes, you need to write them back

    textDataFromEntity[textEntity] = textData;

    (note if you do this you'll probably run into safety issues I don't have time to explain at the moment)
     
  3. voidraizer

    voidraizer

    Joined:
    Dec 20, 2013
    Posts:
    6
    Thanks for that, I'll look into it.

    I'm a bit confused though because it is my understanding that the TriggerJob must be a struct. How would you handle any kind of data modification within a trigger if this is the implementation but leads to other issues?
     
  4. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,627
    It's not the job that's the issue.

    This is what you're doing


    What is the value of myArray[0]?
    Obviously still 0, you haven't set it. You've only written to the scoped version myInt.
    You need to write to the array, myArray[0] = myInt;

    Now go back to your component data.

    Code (CSharp):
    1. SpawnComponent spawnData = spawnDataFromEntity[spawnEntity];
    2. spawnData.doSpawn = true;
    What is the value of spawnDataFromEntity[spawnEntity].doSpawn?
    It's the same as the previous example. It's still false.
    You need to write it back

    spawnDataFromEntity[spawnEntity] = spawnData;

    You're working with structs not classes.