Getting spatial queries working and making them efficient

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:

    ContactFilter2D filter = new ContactFilter2D();
    filter.SetLayerMask(LayerMask.GetMask("Enemies"));
    List<Collider2D> hits = new List<Collider2D>();
    Physics2D.OverlapCircle(rb.transform.position, explosionRadius, filter, hits);

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)

        var physicsWorldSystem = World.DefaultGameObjectInjectionWorld.GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>();
        var collisionWorld = world.CollisionWorld;
        NativeList<int> hitsIndices = new NativeList<int>(Allocator.Temp);

        CollisionFilter filter = new CollisionFilter
        {
            BelongsTo = ~0u,
            CollidesWith = ~0u,
            GroupIndex = 0
        };
        //Check for nearby unitsgroup already existing
        Aabb aabb = new Aabb
        {
            Min = center + new float3(-radius, 0, -radius),
            Max = center + new float3(radius, 1, radius)
        };
        OverlapAabbInput overlapAabbInput = new OverlapAabbInput
        {
            Aabb = aabb,
            Filter = filter,
        };

        bool haveHits = collisionWorld.OverlapAabb(overlapAabbInput, ref hitsIndices);
        var bodies = collisionWorld.Bodies;

        for (int i = 0; i < hitsIndices.Length; i++)
        {
            int rigidBodyIndex = hitsIndices[i];
            RigidBody rigidBody = bodies[rigidBodyIndex];
            PhysicsWorldExtensions.ApplyLinearImpulse(world, rigidBodyIndex, new float3(1, 1, 0) * 500);
        }

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?

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.

    protected override void OnUpdate()
    {
        int radius = 10;
        for (;explosions > 0; explosions--)
        {
            var location = playerQuery.ToComponentDataArray<Translation>(Allocator.Temp);
            if(location.Length > 0)
            {
                var physicsWorldSystem = World.DefaultGameObjectInjectionWorld.GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>();

                /*                PushAwayFromPointJob moveJob = new PushAwayFromPointJob { dt = Time.DeltaTime, center = location[0].Value, force = 500, radius = 10, world = physicsWorldSystem.PhysicsWorld };
                                moveJob.Schedule(entityQuery);*/

                var collisionWorld = physicsWorldSystem.PhysicsWorld.CollisionWorld;
                var world = physicsWorldSystem.PhysicsWorld;
                NativeList<int> hitsIndices = new NativeList<int>(Allocator.Temp);

                CollisionFilter filter = new CollisionFilter
                {
                    BelongsTo = 1 << 1,
                    CollidesWith = 1 << 0,
                    GroupIndex = 0
                };
                //Check for nearby unitsgroup already existing
                Aabb aabb = new Aabb
                {
                    Min = location[0].Value + new float3(-radius, -radius, -1),
                    Max = location[0].Value + new float3(radius, radius, 1)
                };
                OverlapAabbInput overlapAabbInput = new OverlapAabbInput
                {
                    Aabb = aabb,
                    Filter = filter,
                };

                collisionWorld.OverlapAabb(overlapAabbInput, ref hitsIndices);
                var bodies = collisionWorld.Bodies;
                var sqrRadius = radius * radius;

                for (int i = 0; i < hitsIndices.Length; i++)
                {
                    int rigidBodyIndex = hitsIndices[i];
                    RigidBody rigidBody = bodies[rigidBodyIndex];
                    Translation position = GetComponent<Translation>(rigidBody.Entity);
                    if (math.lengthsq(location[0].Value - position.Value) <= sqrRadius)
                    {
                        float3 direction = position.Value - location[0].Value;
                        float falloff = radius / math.length(direction);
                        float3 force = math.normalize(direction) * 1 * falloff * Time.DeltaTime;
                        PhysicsWorldExtensions.ApplyLinearImpulse(world, rigidBodyIndex, force);
                    }
                }
            }
        }
    }

I would still love feedback if anyone has any!

1 Like