Search Unity

I want to make a HitBrick game with ECS and new Physics,but I met some problems

Discussion in 'Physics for ECS' started by Deleted User, Jul 7, 2019.

  1. Deleted User

    Deleted User

    Guest

    I use the ConverToEntity,Physics Shape,Physics Body, the collision between ball and bricks work well.Then I wrote a "ColllisionJob" derived from ICollisionEventsJob. I'm going to destroy the brick and instantiate a new ball in this code.But it reports an error "UnityException: scope can only be called from the main thread.". So I add a component named "InstantiateBall" to the ball, and then write a system named "InstantiateBallSystem", which is derived from the ComponentSystem, and I get all entities with "InstantiateBall" component, and then create a new ball and remove the "InstantiateBall" component, but it reports" type of component: InstantiateBall has been added to the entity."What's more, it creates a lot of balls.How do I modify my code?
     
    Last edited by a moderator: Jul 7, 2019
    S_Darkwell likes this.
  2. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    I think you need to be using a command buffer so that you can ensure the instantiation only occurs on the main thread.

    Could it be that a ball in a collision is the point where you add new balls which is where they are probably going to be in a collision state as well.

    You may want to look at the order of your systems e.g. CreateBall might be before DestroyBrick and especially where the Collision Checking occurs.

    Also posting your code can really help developers help you.
     
  3. Deleted User

    Deleted User

    Guest

    Thank you for response. Maybe you are right.The code is shown below
     

    Attached Files:

  4. Arowx

    Arowx

    Joined:
    Nov 12, 2009
    Posts:
    8,194
    You can just past the code into the forum e.g.

    Code (CSharp):
    1. public class InstiateBallSystem : ComponentSystem
    2. {
    3.     public EntityCommandBufferSystem bufferSystem;
    4.     protected override void OnCreate()
    5.     {
    6.         bufferSystem = World.Active.GetOrCreateSystem<EntityCommandBufferSystem>();
    7.     }
    8.     protected override void OnUpdate()
    9.     {
    10.         var commandBuffer = bufferSystem.CreateCommandBuffer();
    11.         var time = Time.time;
    12.         Entities.ForEach((Entity entity, ref Translation trans, ref InstantiateBall ball) =>
    13.         {
    14.             var newball = commandBuffer.Instantiate(entity);
    15.             commandBuffer.RemoveComponent<InstantiateBall>(entity);
    16.             commandBuffer.RemoveComponent<InstantiateBall>(newball);
    17.             commandBuffer.SetComponent(newball, new PhysicsVelocity
    18.             {
    19.                 Linear = math.normalize(new float3(UnityEngine.Random.Range(-100f, 100f), UnityEngine.Random.Range(0f, 100f), 0)) * 40f
    20.             });
    21.  
    22.         });
    23.  
    24.     }
    25. }
    26.  
    27. public class CollisionSystem : JobComponentSystem
    28. {
    29.     EndSimulationEntityCommandBufferSystem endSimCommandBuffer;
    30.     BuildPhysicsWorld buildPhysicsWorldSystem;
    31.     StepPhysicsWorld stepPhysicsWorldSystem;
    32.     protected override void OnCreate()
    33.     {
    34.         endSimCommandBuffer = World.GetOrCreateSystem<EndSimulationEntityCommandBufferSystem>();
    35.         buildPhysicsWorldSystem = World.GetOrCreateSystem<BuildPhysicsWorld>();
    36.         stepPhysicsWorldSystem = World.GetOrCreateSystem<StepPhysicsWorld>();
    37.         base.OnCreate();
    38.     }
    39.     protected override JobHandle OnUpdate(JobHandle inputDeps)
    40.     {
    41.         var job = new CollisionJob
    42.         {
    43.             commandBuffer = endSimCommandBuffer.CreateCommandBuffer(),
    44.             balls = GetComponentDataFromEntity<BallTag>(false),
    45.             bricks = GetComponentDataFromEntity<BrickTag>(false),
    46.             Instiates = GetComponentDataFromEntity<InstantiateBall>(true),
    47.         }.Schedule(stepPhysicsWorldSystem.Simulation, ref buildPhysicsWorldSystem.PhysicsWorld, inputDeps);
    48.         endSimCommandBuffer.AddJobHandleForProducer(job);
    49.         job.Complete();
    50.         return job;
    51.     }
    52.     public struct CollisionJob : ICollisionEventsJob
    53.     {
    54.         [ReadOnly] public ComponentDataFromEntity<BrickTag> bricks;
    55.         [ReadOnly] public ComponentDataFromEntity<BallTag> balls;
    56.         [ReadOnly] public ComponentDataFromEntity<InstantiateBall> Instiates;
    57.         [ReadOnly] public EntityCommandBuffer commandBuffer;
    58.         public float time;
    59.         public void Execute(Unity.Physics.CollisionEvent collisionEvent)
    60.         {
    61.             EntityPair pair = collisionEvent.Entities;
    62.             if (Instiates.Exists(pair.EntityA) || Instiates.Exists(pair.EntityB))
    63.             {
    64.                 return;
    65.             }
    66.             if (bricks.Exists(pair.EntityA) && balls.Exists(pair.EntityB))
    67.             {
    68.                 commandBuffer.DestroyEntity(pair.EntityA);
    69.                 if (Instiates.Exists(pair.EntityA) || Instiates.Exists(pair.EntityB))
    70.                 {
    71.                     return;
    72.                 }
    73.                 commandBuffer.AddComponent(pair.EntityB, new InstantiateBall { });              
    74.             }
    75.             else if (balls.Exists(pair.EntityA) && bricks.Exists(pair.EntityB))
    76.             {
    77.                 commandBuffer.DestroyEntity(pair.EntityB);
    78.                 if (Instiates.Exists(pair.EntityA) || Instiates.Exists(pair.EntityB))
    79.                 {
    80.                     return;
    81.                 }
    82.                 commandBuffer.AddComponent(pair.EntityA, new InstantiateBall { });
    83.             }
    84.         }
    85.     }
    86. }
    87.  
    88.  
     
    Ninjars likes this.
  5. temps12

    temps12

    Joined:
    Nov 28, 2014
    Posts:
    41
    I think it is because the command buffer is consumed after the job, in this case at the EndSimBarrier. You check if the entities already has a component on them but it wont take the ones already added this frame in the command buffer in consideration. If an entity is colliding more than once a frame it will add the component multiple times.

    Edit: Removed my old answer because I didn't fully read the question.
     
    Last edited: Jul 7, 2019
  6. Deleted User

    Deleted User

    Guest

    OK,I got it.
     
  7. dstilwagen

    dstilwagen

    Joined:
    Mar 14, 2018
    Posts:
    36
    In the InstiateBallSystem class you are trying to get EntityCommandBufferSystem but that is an abstract class. I'm not sure how this is handled but my guess is that it will return the first barrier system that is found. Instead since you are using a ComponentSystem you should use PostUpdateCommands which will execute all the commands for it's command buffer just after the update function is called instead of at the barrier.
     
  8. Deleted User

    Deleted User

    Guest

    I have done it, but it doesn't work.
     
  9. Ninjars

    Ninjars

    Joined:
    Feb 13, 2013
    Posts:
    7
    Just wanted to say huge thanks for this post - I'd been really struggling to get my head around collisions in this system, and this really helped unblock me!