Search Unity

Resolved How do I raycast in an old state of the world inside a job running for several frames?

Discussion in 'Physics for ECS' started by Interjection, Jul 17, 2020.

  1. Interjection

    Interjection

    Joined:
    Jun 18, 2020
    Posts:
    63
    I'm still new to Entities and thought the SSCCE below would work:

    Code (CSharp):
    1. public class MyTestComponent : UnityEngine.MonoBehaviour {
    2.  
    3.     private MyTest job;
    4.     private Unity.Jobs.JobHandle handle;
    5.  
    6.     void FixedUpdate() {
    7.         handle.Complete();
    8.         Unity.Physics.Systems.BuildPhysicsWorld buildPhysicsWorld = Unity.Entities.World.DefaultGameObjectInjectionWorld.GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>();
    9.         job.cw = buildPhysicsWorld.PhysicsWorld.CollisionWorld;
    10.         handle = Unity.Jobs.IJobParallelForExtensions.Schedule<MyTest>(job, 500, 50);
    11.     }
    12.  
    13. }
    14.  
    15. public struct MyTest : Unity.Jobs.IJobParallelFor {
    16.     [Unity.Collections.ReadOnly]
    17.     public Unity.Physics.CollisionWorld cw;
    18.     public void Execute(int index) {
    19.         //do nothing for now, planning to do cw.CastRay()
    20.     }
    21. }
    However I'm getting:
    InvalidOperationException: The previously scheduled job MyTest reads from the NativeArray MyTest.cw.m_Bodies. You must call JobHandle.Complete() on the job MyTest, before you can deallocate the NativeArray safely.


    If I move
    handle.Complete();
    to the end of FixedUpdate() everything works but not if have it in the beginning like I need. I want to have units in my game raycast their vision from their predicted future positions next keyframe, then simply apply the vision when the keyframe is reached. That's why I need to raycast an old state of the world for several frames, it can't just finish on the same frame.

    How am I supposed to do this?
    Do I need to call some kind of "make permanent copy" method instead of using
    .PhysicsWorld.CollisionWorld
    ?
     
  2. petarmHavok

    petarmHavok

    Joined:
    Nov 20, 2018
    Posts:
    461
    I think CollisionWorld.Clone() is what you need in your example. Let me know if it works for you!
     
  3. Interjection

    Interjection

    Joined:
    Jun 18, 2020
    Posts:
    63
    @petarmHavok: That hit the spot, thank you! Working code below.

    Code (CSharp):
    1. public class MyTestComponent : UnityEngine.MonoBehaviour {
    2.  
    3.     private MyTest job;
    4.     private Unity.Jobs.JobHandle handle;
    5.  
    6.     void FixedUpdate() {
    7.         OnDestroy();  //modified line
    8.         Unity.Physics.Systems.BuildPhysicsWorld buildPhysicsWorld = Unity.Entities.World.DefaultGameObjectInjectionWorld.GetExistingSystem<Unity.Physics.Systems.BuildPhysicsWorld>();
    9.         job.cw = buildPhysicsWorld.PhysicsWorld.CollisionWorld.Clone();  //modified line
    10.         handle = Unity.Jobs.IJobParallelForExtensions.Schedule<MyTest>(job, 500, 50);
    11.     }
    12.  
    13.     void OnDestroy() {  //new method
    14.         handle.Complete();
    15.         job.cw.Dispose();
    16.     }
    17.  
    18. }
    19.  
    20. public struct MyTest : Unity.Jobs.IJobParallelFor {
    21.     [Unity.Collections.ReadOnly]
    22.     public Unity.Physics.CollisionWorld cw;
    23.     public void Execute(int index) {
    24.         //do nothing for now, planning to do cw.CastRay()
    25.     }
    26. }
     
    petarmHavok likes this.