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

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.