Search Unity

Resolved Set Collider during runtime

Discussion in 'DOTS Physics' started by slushieboy99, Sep 6, 2021.

  1. slushieboy99

    slushieboy99

    Joined:
    Aug 29, 2014
    Posts:
    31
    Hello,
    I'm trying to set collider data on a single entity but I get the error "InvalidOperationException: Adding/removing components or changing position/rotation/velocity/collider ECS data on dynamic entities during physics step".
    I looked through the example at https://github.com/Unity-Technologi...Modify/Scripts/ChangeColliderTypeAuthoring.cs, but I only need to update component data for one entity at a time, so I'd rather not create an entire new systembase class for that. Is there any way to schedule a specific function to run when a physics step is not? Below is my code:


    Code (CSharp):
    1. entityManager.SetComponentData(meshEntity, new PhysicsCollider {
    2.             Value = output[0]
    3.         });
    Where output[0] is a physicscollider blobassetreference.
     
  2. steveeHavok

    steveeHavok

    Joined:
    Mar 19, 2019
    Posts:
    480
    The problem is that the
    BuildPhysicsWorld
    and
    ExportPhysicsWorld
    use the same Entity Query to get the physics related entities. If you change data yourself between these systems then the order of entities could be different and the export writes the data into incorrect components, or you make changes to the ECS data and the export overwrites you changes.

    Instead of setting the
    ComponentData 
    directly, you could create an
    EntityCommandBuffer 
    from the
    EndFixedStepSimulationEntityCommandBufferSystem
    and have the data set after the fixed step has complete.
     
    slushieboy99 likes this.
  3. slushieboy99

    slushieboy99

    Joined:
    Aug 29, 2014
    Posts:
    31
    My understanding is that command buffers can only be used in a System. I was hoping to find a solution where I don't need to create any systems.
     
  4. slushieboy99

    slushieboy99

    Joined:
    Aug 29, 2014
    Posts:
    31
    @steveeHavok
    Okay so I've gone ahead and tried to set the physics collider in a system, but I'm still getting lots of the same errors.


    Code (CSharp):
    1. using PCollider = Unity.Entities.BlobAssetReference<Unity.Physics.Collider>;
    2.  
    3. public struct PhysicsColliderHolder : IComponentData { public PCollider held; }
    4.  
    5. [UpdateInGroup(typeof(FixedStepSimulationSystemGroup))]
    6. [UpdateBefore(typeof(BuildPhysicsWorld))]
    7. public class ApplyMeshColliderJobSystem : SystemBase {
    8.     protected override void OnUpdate() {
    9.         using (var commandBuffer = new EndFixedStepSimulationEntityCommandBufferSystem().CreateCommandBuffer()) {
    10.             Entities
    11.             .WithName("terrain_chunk")
    12.             .ForEach((Entity entity, ref PhysicsColliderHolder holder) => {
    13.                 PhysicsCollider collider = new PhysicsCollider() {
    14.                     Value = holder.held
    15.                 };
    16.                 commandBuffer.SetComponent(entity, collider);
    17.                 commandBuffer.RemoveComponent(entity, typeof(PhysicsColliderHolder));
    18.             }).Run();
    19.             commandBuffer.Playback(EntityManager);
    20.         }
    21.     }
    22. }
    I'm also getting an Object Reference Not Set to Instance of Object error at
    var world = World.Unmanaged;
    in EntityCommandBufferSystem.CreateCommandBuffer();

    I can't find any examples of someone trying to set a collider at runtime, except for the example above which seems to just swap two existing collider. I tried directly modifying that code and it did not work so I'm a little lost here. If anyone has examples I can look at for how to do this properly that would be really helpful.

    I also can't seem to add a
    BlobAssetReference<Unity.Physics.Collider>
    to an entity even if it's not in a PhysicsCollider struct. As you can see, I tried to add a new component
    public struct PhysicsColliderHolder : IComponentData { public PCollider held; }
    to get the generated collider into the system, but when I add this component to an entity I get the same physics step error. So on top of all this, I have no idea how to actually get the collider I want to add to an entity into the system, it's quite the conundrum haha.
     
    Last edited: Sep 10, 2021
  5. slushieboy99

    slushieboy99

    Joined:
    Aug 29, 2014
    Posts:
    31
    Alternatively, when I try to do the same thing outside of a system, I get all the same errors:

    Code (CSharp):
    1. EntityCommandBuffer commandBuffer = new EndFixedStepSimulationEntityCommandBufferSystem().CreateCommandBuffer();
    2.         PhysicsCollider collider = new PhysicsCollider { Value = output[0] };
    3.         commandBuffer.SetComponent(meshEntity, collider);
    4.         commandBuffer.Playback(entityManager);
    This is ideally what I'd like my code to be as it is much simpler for this solution than a System, but I still get the null object reference on World.Unmanaged and my console is still spammed with Physics Step errors.
     
  6. slushieboy99

    slushieboy99

    Joined:
    Aug 29, 2014
    Posts:
    31
    Okay after some more research I got this working.


    Code (CSharp):
    1. PhysicsCollider collider = new PhysicsCollider { Value = output[0] };
    2.         EntityCommandBufferSystem ecbSystem = World.DefaultGameObjectInjectionWorld.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    3.         EntityCommandBuffer buffer = ecbSystem.CreateCommandBuffer();
    4.         buffer.SetComponent(meshEntity, collider);
    A few notes as an aside, many of the docs on EntityBufferSystems seem to be outdated. I messed around with EntityCommandBufferSystem.PostUpdateCommands a lot which only seemed to lead to EntityCommandBuffer not initialized errors, but I'm curious if anyone knows how to currently use this as it's seemingly different than it is in the documentation.
     
unityunity