Search Unity

Feedback Getting spatial queries working and making them efficient

Discussion in 'Physics for ECS' started by Noomnahor, May 4, 2022.

  1. Noomnahor

    Noomnahor

    Joined:
    Jan 20, 2018
    Posts:
    14
    I have a large collection of entities that exist in a Physics World, and I would like to apply a force to a group of them that are within a specific area.
    For context, in a classic monobehavior I would do something like this:
    Code (CSharp):
    1.        
    2.     ContactFilter2D filter = new ContactFilter2D();
    3.     filter.SetLayerMask(LayerMask.GetMask("Enemies"));
    4.     List<Collider2D> hits = new List<Collider2D>();
    5.     Physics2D.OverlapCircle(rb.transform.position, explosionRadius, filter, hits);
    6.  
    I would like to achieve something similar in DOTS. I have read through the docs on spatial queries and am struggling to understand the implementation of the provided examples, I'm not sure where this code would exist, and what I should do with the returned rigidBodies. My current attempt is to create a SystemBase that handles everything, but aside from it just straight up not working, I'm also unsure if this will be efficient and if this code should exist in a Job somehow. Here's my existing code:

    (In the onUpdate method of a SystemBase class)
    Code (CSharp):
    1.  
    2.         var physicsWorldSystem = World.DefaultGameObjectInjectionWorld.GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>();
    3.         var collisionWorld = world.CollisionWorld;
    4.         NativeList<int> hitsIndices = new NativeList<int>(Allocator.Temp);
    5.  
    6.         CollisionFilter filter = new CollisionFilter
    7.         {
    8.             BelongsTo = ~0u,
    9.             CollidesWith = ~0u,
    10.             GroupIndex = 0
    11.         };
    12.         //Check for nearby unitsgroup already existing
    13.         Aabb aabb = new Aabb
    14.         {
    15.             Min = center + new float3(-radius, 0, -radius),
    16.             Max = center + new float3(radius, 1, radius)
    17.         };
    18.         OverlapAabbInput overlapAabbInput = new OverlapAabbInput
    19.         {
    20.             Aabb = aabb,
    21.             Filter = filter,
    22.         };
    23.  
    24.         bool haveHits = collisionWorld.OverlapAabb(overlapAabbInput, ref hitsIndices);
    25.         var bodies = collisionWorld.Bodies;
    26.  
    27.         for (int i = 0; i < hitsIndices.Length; i++)
    28.         {
    29.             int rigidBodyIndex = hitsIndices[i];
    30.             RigidBody rigidBody = bodies[rigidBodyIndex];
    31.             PhysicsWorldExtensions.ApplyLinearImpulse(world, rigidBodyIndex, new float3(1, 1, 0) * 500);
    32.         }
    33.  
    The overlapAABB seems to work, I'm getting a list of RigiBodyIndex's, however no matter how I create my float3 Impulse everything is refusing to move.

    So my questions are:
    - Is there an obvious reason why ApplyLinearImpulse isn't working here?
    - Is this the best approach?
    - If it makes more sense that this be run in a Job (or if the movement/impulse should be in a job) how can I use a JobQuery or something similar to ensure the Job only runs on the discovered RigidBodies?
     
  2. Noomnahor

    Noomnahor

    Joined:
    Jan 20, 2018
    Posts:
    14
    So I got it working, I think it was my CollisionFilter, not certain, here's my updated code. Note: the AABB is a thin rectangular prism oriented for a 2D environment.

    Code (CSharp):
    1.     protected override void OnUpdate()
    2.     {
    3.         int radius = 10;
    4.         for (;explosions > 0; explosions--)
    5.         {
    6.             var location = playerQuery.ToComponentDataArray<Translation>(Allocator.Temp);
    7.             if(location.Length > 0)
    8.             {
    9.                 var physicsWorldSystem = World.DefaultGameObjectInjectionWorld.GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>();
    10.  
    11.                 /*                PushAwayFromPointJob moveJob = new PushAwayFromPointJob { dt = Time.DeltaTime, center = location[0].Value, force = 500, radius = 10, world = physicsWorldSystem.PhysicsWorld };
    12.                                 moveJob.Schedule(entityQuery);*/
    13.  
    14.                 var collisionWorld = physicsWorldSystem.PhysicsWorld.CollisionWorld;
    15.                 var world = physicsWorldSystem.PhysicsWorld;
    16.                 NativeList<int> hitsIndices = new NativeList<int>(Allocator.Temp);
    17.  
    18.                 CollisionFilter filter = new CollisionFilter
    19.                 {
    20.                     BelongsTo = 1 << 1,
    21.                     CollidesWith = 1 << 0,
    22.                     GroupIndex = 0
    23.                 };
    24.                 //Check for nearby unitsgroup already existing
    25.                 Aabb aabb = new Aabb
    26.                 {
    27.                     Min = location[0].Value + new float3(-radius, -radius, -1),
    28.                     Max = location[0].Value + new float3(radius, radius, 1)
    29.                 };
    30.                 OverlapAabbInput overlapAabbInput = new OverlapAabbInput
    31.                 {
    32.                     Aabb = aabb,
    33.                     Filter = filter,
    34.                 };
    35.  
    36.                 collisionWorld.OverlapAabb(overlapAabbInput, ref hitsIndices);
    37.                 var bodies = collisionWorld.Bodies;
    38.                 var sqrRadius = radius * radius;
    39.  
    40.                 for (int i = 0; i < hitsIndices.Length; i++)
    41.                 {
    42.                     int rigidBodyIndex = hitsIndices[i];
    43.                     RigidBody rigidBody = bodies[rigidBodyIndex];
    44.                     Translation position = GetComponent<Translation>(rigidBody.Entity);
    45.                     if (math.lengthsq(location[0].Value - position.Value) <= sqrRadius)
    46.                     {
    47.                         float3 direction = position.Value - location[0].Value;
    48.                         float falloff = radius / math.length(direction);
    49.                         float3 force = math.normalize(direction) * 1 * falloff * Time.DeltaTime;
    50.                         PhysicsWorldExtensions.ApplyLinearImpulse(world, rigidBodyIndex, force);
    51.                     }
    52.                 }
    53.             }
    54.         }
    55.     }
    I would still love feedback if anyone has any!
     
    bb8_1 likes this.