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

Entity destruction on collision through jobs?

Discussion in 'Entity Component System' started by Fluidmind, May 22, 2020.

  1. Fluidmind

    Fluidmind

    Joined:
    Jan 10, 2020
    Posts:
    28
    I've been trying to muddle my way through the examples, and found the ModifiableJoacobiansJob. Am I correct in reading that this job is scheduled on collision of entities? If I try destroying or adding components from the Jacobian jobs, I'm missing the job index to pass to those methods.I was looking for an ECS jobs way to destroy entities on collisions with certain other entities, but I feel as though I'm lost on how to do this.
     
  2. AvAars

    AvAars

    Joined:
    Apr 26, 2020
    Posts:
    1
    I guess you're looking for the ICollisionEventsJob, like in this example
     
  3. Fluidmind

    Fluidmind

    Joined:
    Jan 10, 2020
    Posts:
    28
    OK, I tried adapting it, but I think I've done something terrible. So here's the system I'm trying to get working:

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using Unity.Collections;
    5. using Unity.Entities;
    6. using Unity.Entities.UniversalDelegates;
    7. using Unity.Jobs;
    8. using Unity.Physics;
    9. using Unity.Physics.Extensions;
    10. using Unity.Physics.Systems;
    11. using Unity.Transforms;
    12. using UnityEditorInternal;
    13. using UnityEngine;
    14.  
    15. public struct DespawnMark : IComponentData { }
    16.  
    17.  
    18.  
    19. [UpdateBefore(typeof(StepPhysicsWorld))]
    20. public class DespawnIntersectionSystem : JobComponentSystem
    21. {
    22.     private NativeList<Entity> _toDespawn;
    23.     private DespawnDetectorJob _despawnDetectorJob;
    24.     private DespawnEnqueueJob _despawnEnqueueJob;
    25.     //public ComponentDataFromEntity<DespawnIntersection> despawner;
    26.     StepPhysicsWorld _StepPhysicsWorld;
    27.     EntityQuery _DepawnerGroup;
    28.  
    29.     protected override void OnCreate()
    30.     {
    31.         _StepPhysicsWorld = World.GetOrCreateSystem<StepPhysicsWorld>();
    32.         _DepawnerGroup = GetEntityQuery(new EntityQueryDesc
    33.         {
    34.             All = new ComponentType[] {typeof(DespawnIntersection)}
    35.         });
    36.         _toDespawn = new NativeList<Entity>(2, Allocator.Persistent);
    37.         _despawnDetectorJob = new DespawnDetectorJob
    38.         {
    39.             toDespawn = _toDespawn,
    40.             despawner = new ComponentDataFromEntity<DespawnIntersection>()
    41.         };
    42.         _despawnEnqueueJob = new DespawnEnqueueJob
    43.         {
    44.             toDespawn = _toDespawn
    45.         };
    46.     }
    47.  
    48.     protected override void OnDestroy()
    49.     {
    50.         _toDespawn.Dispose();
    51.     }
    52.  
    53.     struct DespawnDetectorJob : ICollisionEventsJob
    54.     {
    55.         public NativeList<Entity> toDespawn;
    56.         Entity entityA;
    57.         Entity entityB;
    58.         public ComponentDataFromEntity<DespawnIntersection> despawner;
    59.         public void Execute(CollisionEvent collisionEvent)
    60.         {
    61.             entityA = collisionEvent.Entities.EntityA;
    62.             entityB = collisionEvent.Entities.EntityB;
    63.  
    64.             if (despawner.Exists(entityB)) toDespawn.Add(entityA);
    65.             if (despawner.Exists(entityA)) toDespawn.Add(entityB);
    66.  
    67.  
    68.         }
    69.     }
    70.  
    71.     struct DespawnEnqueueJob : IJobFor
    72.     {
    73.         [ReadOnly]
    74.         public NativeList<Entity> toDespawn;
    75.         public void Execute(int index)
    76.         {
    77.             EntityCommandBuffer.Concurrent concurrent = new EntityCommandBuffer.Concurrent();
    78.             for (int i = 0; i <= toDespawn.Length; i++)
    79.             {
    80.                 concurrent.DestroyEntity(index, toDespawn[i]);
    81.             }
    82.         }
    83.     }
    84.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    85.     {
    86.  
    87.         SimulationCallbacks.Callback findDespawnerCollisions = (ref ISimulation simulaton, ref PhysicsWorld world, JobHandle inDeps) =>
    88.         {
    89.             return _despawnDetectorJob.Schedule(simulaton, ref world, inDeps);
    90.         };
    91.         //SimulationCallbacks.Callback enqueueDespawns = (ref ISimulation simulaton, ref PhysicsWorld world, JobHandle inDeps) =>
    92.         //{
    93.         //    return _despawnEnqueueJob.Schedule(simulaton, ref world, inDeps);
    94.         //};
    95.         _StepPhysicsWorld.EnqueueCallback(SimulationCallbacks.Phase.PostSolveJacobians, findDespawnerCollisions, inputDeps);
    96.         //_StepPhysicsWorld.EnqueueCallback(SimulationCallbacks.Phase.PostSolveJacobians, enqueueDespawns, inputDeps);
    97.         _despawnEnqueueJob.Run<DespawnEnqueueJob>(_toDespawn.Length);
    98.  
    99.         return inputDeps;
    100.     }
    101. }
    102.  
    But..when I enter play mode, I get this exception:

    InvalidOperationException: The NativeContainer DespawnDetectorJob.UserJobData.despawner has not been assigned or constructed. All containers must be valid when scheduling a job.

    I'm instantiating it in OnCreate, and passing it into the job definition in the same method.

    Also, I needed to use IJobFor to get the entity destroy command queued, which caused a problem when I call EnqueueCallback because "The type 'DespawnIntersectionSystem.DespawnEnqueueJob' cannot be used as type parameter 'T' in the generic type or method 'IBodyPairsJobExtensions.Schedule<T>(T, ISimulation, ref PhysicsWorld, JobHandle)'. There is no boxing conversion from 'DespawnIntersectionSystem.DespawnEnqueueJob' to 'Unity.Physics.IBodyPairsJobBase'."

    Where should I go from here?
     
  4. RecursiveEclipse

    RecursiveEclipse

    Joined:
    Sep 6, 2018
    Posts:
    298
    You don't use "new ComponentDataFromEntity", no data would be there. You use GetComponentDataFromEntity which is inherited from SystemBase.
     
  5. Fluidmind

    Fluidmind

    Joined:
    Jan 10, 2020
    Posts:
    28
    I tried updating the call,got the below error. So I figured maybe reinstaniate the job in OnUpdate, same exception. Made the ComponentDataFromEntity a class variable that I updated from OnUpdate, and still got the below exception.
    Code (CSharp):
    1. public class DespawnIntersectionSystem : JobComponentSystem
    2. {
    3.     private NativeList<Entity> _toDespawn;
    4.     private DespawnDetectorJob _despawnDetectorJob;
    5.     private DespawnEnqueueJob _despawnEnqueueJob;
    6.     //public ComponentDataFromEntity<DespawnIntersection> despawner;
    7.     StepPhysicsWorld _StepPhysicsWorld;
    8.     EntityQuery _DepawnerGroup;
    9.     ComponentDataFromEntity<DespawnIntersection> _despawner;
    10.  
    11. ...
    12.  
    13.  
    14.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    15.     {
    16.         _DepawnerGroup = GetEntityQuery(new EntityQueryDesc
    17.         {
    18.             All = new ComponentType[] { typeof(DespawnIntersection) }
    19.         });
    20.         _toDespawn = new NativeList<Entity>(2, Allocator.Persistent);
    21.         _despawner = GetComponentDataFromEntity<DespawnIntersection>();
    22.         _despawnDetectorJob = new DespawnDetectorJob
    23.         {
    24.             toDespawn = _toDespawn,
    25.             despawner = _despawner
    26.         };
    27.         _despawnEnqueueJob = new DespawnEnqueueJob
    28.         {
    29.             toDespawn = _toDespawn
    30.         };
    31.  
    32.         SimulationCallbacks.Callback findDespawnerCollisions = (ref ISimulation simulaton, ref PhysicsWorld world, JobHandle inDeps) =>
    33.         {
    34.             return _despawnDetectorJob.Schedule(simulaton, ref world, inDeps);
    35.         };
    36.         //SimulationCallbacks.Callback enqueueDespawns = (ref ISimulation simulaton, ref PhysicsWorld world, JobHandle inDeps) =>
    37.         //{
    38.         //    return _despawnEnqueueJob.Schedule(simulaton, ref world, inDeps);
    39.         //};
    40.         _StepPhysicsWorld.EnqueueCallback(SimulationCallbacks.Phase.PostSolveJacobians, findDespawnerCollisions, inputDeps);
    41.         //_StepPhysicsWorld.EnqueueCallback(SimulationCallbacks.Phase.PostSolveJacobians, enqueueDespawns, inputDeps);
    42.         _despawnEnqueueJob.Run<DespawnEnqueueJob>(_toDespawn.Length);
    43.  
    44.         return inputDeps;
    45.     }
    46.  
    47.  
    InvalidOperationException: The NativeContainer DespawnDetectorJob.UserJobData.despawner has been deallocated. All containers must be valid when scheduling a job.

    So there's something about the memory I'm missing when it comes to operating these jobs. would I need to pass it as a NativeArray?
     
  6. RecursiveEclipse

    RecursiveEclipse

    Joined:
    Sep 6, 2018
    Posts:
    298
    I think when the callback tries to get the job, the _despawner that was referenced no longer exists. Try removing the _despawner variable from the system and give it GetComponentDataFromEntity exactly like the physics example above.

    Also in the new code you posted, _toDespawn is creating another array each update which is never disposed.