Trouble getting CollisionWorld.CalculateDistance() to work.

Hi,
I am trying to get all enemys in a certain range around my tower into its Dynamic buffer.
but “CollisionWorld.CalculateDistance()” either doesnt work at all, works but throws a plethera of errors or Works when using without burst and with run instead of schedule parallel.

I’m unsure as to how to fix the issue.

public class TargetingSystem : SystemBase
{
    private BuildPhysicsWorld buildPhysicsWorld;
    private EndFramePhysicsSystem endFramePhysicsSystem;

    protected override void OnCreate()
    {
        this.buildPhysicsWorld = World.GetExistingSystem<BuildPhysicsWorld>();
        this.endFramePhysicsSystem = World.GetExistingSystem<EndFramePhysicsSystem>();
    }

    protected override void OnUpdate()
    {
        var collisionWorld = this.buildPhysicsWorld.PhysicsWorld.CollisionWorld;
        this.Dependency =
            JobHandle.CombineDependencies(this.Dependency, this.endFramePhysicsSystem.GetOutputDependency());


        Entities.WithAll<TagTower>().WithBurst().ForEach((ref DynamicBuffer<Target> targets) =>
        {
            var hits = new NativeList<DistanceHit>(Allocator.Temp);

            var filter = new CollisionFilter()
            {
                BelongsTo = ~0u,
                CollidesWith = ~0u,
                GroupIndex = 0
            };

            var distanceInput = new PointDistanceInput()
            {
                Position = float3.zero,
                MaxDistance = 10f,
                Filter = filter
            };

            collisionWorld.CalculateDistance(distanceInput, ref hits);

            for (int i = 0; i < hits.Length; i++)
            {
                Debug.Log("Location:  " + hits[i].Position);
                Debug.Log("Entity:  " + hits[i].Entity);
            }

            hits.Dispose();
        }).ScheduleParallel();
    }
}

This returns the expected results, but returns the following errors:
(Removing “collisionWorld.CalculateDistance(distanceInput, ref hits);” resolves all errors)

A Native Collection has not been disposed, resulting in a memory leak. Enable Full StackTraces to get more details.

InvalidOperationException: The previously scheduled job TargetingSystem:<>c__DisplayClass_OnUpdate_LambdaJob0 writes to the Unity.Collections.NativeArray1[Unity.Physics.CollisionFilter] <>c__DisplayClass_OnUpdate_LambdaJob0.JobData.collisionWorld.Broadphase.m_StaticTree.BodyFilters. You are trying to schedule a new job Broadphase: PrepareStaticBodyDataJob, which writes to the same Unity.Collections.NativeArray1[Unity.Physics.CollisionFilter] (via PrepareStaticBodyDataJob.FiltersOut). To guarantee safety, you must include TargetingS

InvalidOperationException: The previously scheduled job TargetingSystem:<>c__DisplayClass_OnUpdate_LambdaJob0 writes to the Unity.Collections.NativeArray1[System.Int32] <>c__DisplayClass_OnUpdate_LambdaJob0.JobData.collisionWorld.Broadphase.m_DynamicTree.BranchCount. You are trying to schedule a new job Broadphase:AllocateDynamicVsStaticNodePairs, which reads from the same Unity.Collections.NativeArray1[System.Int32] (via AllocateDynamicVsStaticNodePairs.dynamicBranchCount). To guarantee safety, you must include TargetingSystem:<>

InvalidOperationException: Adding/removing components or changing position/rotation/velocity/collider ECS data on dynamic entities during physics step

InvalidOperationException: The previously scheduled job Broadphase: PrepareNumStaticBodiesJob writes to the Unity.Collections.NativeArray1[System.Int32] PrepareNumStaticBodiesJob.BuildStaticTree. You must call JobHandle.Complete() on the job Broadphase: PrepareNumStaticBodiesJob, before you can write to the Unity.Collections.NativeArray1[System.Int32] safely.

If i declare CollisionWorld in OnCreate instead of OnUpdate:

public class TargetingSystem : SystemBase
{
    private BuildPhysicsWorld buildPhysicsWorld;
    private EndFramePhysicsSystem endFramePhysicsSystem;
    private CollisionWorld collisionWorld;

    protected override void OnCreate()
    {
        this.buildPhysicsWorld = World.GetExistingSystem<BuildPhysicsWorld>();
        this.endFramePhysicsSystem = World.GetExistingSystem<EndFramePhysicsSystem>();
        collisionWorld = this.buildPhysicsWorld.PhysicsWorld.CollisionWorld;
    }

The error tells me to use

Entities.ForEach Lambda expression uses field ‘collisionWorld’. Either assign the field to a local outside of the lambda expression and use that instead, or use .WithoutBurst() and .Run()

Doing that works fine and i get the expected results without errors.

Is there a way to run this in Parallel without getting all these errors?

I’m gonna try and help you with the original approach to make this work in parallel. You are missing 2 things:

  1. You need
    [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
    [UpdateAfter(typeof(EndFramePhysicsSystem))]
    to make sure your system updates at the exact time.
  2. You also need
    buildPhysicsWorld.AddDependencyToComplete(Dependency)
    at the very end of your OnUpdate() method to inform the BuildPhysicsWorld of the next step that it needs to wait for your jobs to finish.

Let’s start with these 2 and see if there are more changes needed. We can also look into scheduling this at different times (after step, before export or similar).

1 Like