Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Bug Trigger/Collision ignored for certain movement speed. Seems like mysterious bug.

Discussion in 'Editor & General Support' started by Efril, Jun 5, 2020.

  1. Efril

    Efril

    Joined:
    Aug 31, 2013
    Posts:
    82
    Hello all. It seems I found a mysterious collision/trigger bug in Unity. Imagine 3 physics objects in a scene. All of them are in the separate layers (but they can be in the same layer. No matter): Water, Ship and Shell. Colliders of Water and Ship are partially intersected but the collision matrix configured so that they do not interact with each other.
    CollisionMatrix.png
    All 3 objects have kinematic Rigidbodies but I tried, probably, all combinations of Rigidbodies settings including non kinematic with different collision detection methods. Scale of all objects is set to 1.
    Shell position and rotation is set to have intersection point with water inside of the ship collider. Shell script simply moves the shell forward with constant speed by updating position with Rigidbody.MovePosition() method:
    Code (CSharp):
    1.  
    2. private void FixedUpdate()
    3. {
    4.    if (_testing)
    5.    {
    6.        Vector3 position = this.transform.position + this.transform.forward * _startSpeed * Time.fixedDeltaTime;
    7.        _rigidbody.MovePosition(position);
    8.    }
    9. }
    10.  
    It also updates color of triggered object in OnTriggerEnter method. Ocean and Ship objects have special script for this:
    Code (CSharp):
    1.  
    2. private void OnTriggerEnter(Collider other)
    3. {
    4.      Debug.Log(other.name + " triggered");
    5.      other.GetComponent<BugTestHitTarget>().UpdateColor(Color.red);
    6. }
    Now when I set shell speed to 650 meters per second OnTriggerEnter method is called only for the Ocean object. When I set shell speed to greater or lesser values (700 and 300, for example) OnTriggerEnter called for both Ship and Ocean objects which is expected behaviour. Why physics engine dislikes 650 meters per second speed is a mistery. This seems like a bug to me. You can see the described scenario in the video below:

    Besides changing speed this could be fixed by increasing radius of SphereCollider of the shell to 1, for example.
    So why the hell this happen and how I can fix this? In my game shells are moving with their real world speed so 650 meters per second may occur.
    Thanks in advance.
     
    Last edited: Jun 5, 2020
  2. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    It's because the objects are moving too fast for how small they are. Basically, you're moving the object too fast for the physics system to register the overlap. On one frame, the projectile is on one side of the object. On the next frame, it's all the way on the other side of the object. On no frame did the objects actually overlap.

    There are different ways to address this depending on your game, but the easiest way is not to rely on the collision, and instead to raycast every frame from the current position to the place the object should be at the end of the frame based on its current velocity. Then you'll always get the hits.
     
    Efril likes this.
  3. Efril

    Efril

    Joined:
    Aug 31, 2013
    Posts:
    82
    It seems you are right. I just checked it again and when Shell moving at speed of 650 meters per second it never 'stops' inside of the ship in the end of the frame.
    Thank you.
     
  4. Efril

    Efril

    Joined:
    Aug 31, 2013
    Posts:
    82
  5. dgoyette

    dgoyette

    Joined:
    Jul 1, 2016
    Posts:
    4,193
    The different collision detection modes can help with high velocity collisions, but none of them are really going to work with relatively small objects moving very fast.

    At 650m/s, I also wonder if the object is effectively fast enough to just be treated as an instant hit. You might just do a single raycast upon firing the object to decide if it will hit the target. At 650m/s, can you really visually tell that the object is moving? How many seconds (or fractions of a second) does this object remain on the screen at this speed? You might just do a single raycast, then move the projectile along just as a visual effect, without any collision detection on it, setting it to destroy itself after it reaches the raycast hit point.
     
    Efril likes this.
  6. Efril

    Efril

    Joined:
    Aug 31, 2013
    Posts:
    82
    They have to update documentation to notify users that CollisionDetectionMode.ContinuousDynamic is not reliable at hight speed.
    Shell speed decreases from distance so it can be very fast in the beginning but become relatively slow in the end of trajectory at high distance. In the video below shells have approximately 540 m/s speed when camera switches to them:

    I decided to do OverlapSphere + SphereCast every FixedUpdate call.
     
  7. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,553
    That's not a bug.

    Objects in a game do not continuously move, they teleport each frame to new position. Now, new position is calculated based on object's velocity and acceleration, so as long as the object is sufficiently slowly moving, all is well.

    However, when something small moves fast and has thin obstacle, it will simply phase through it. Because objects do not continuously move and instead teleport.

    Continuous dynamic is made to address this problem to a degree.

    Either way with speeds of 650 m/s you should use raycast from old to new position to determine hits.
     
  8. Efril

    Efril

    Joined:
    Aug 31, 2013
    Posts:
    82
    I think this would be true in case of direct manipulation of transfrom.position. But I'm using Rigidbody.MovePosition() method which seems to be designed to make position manipulation work well with physics.

    Anyway I tried to test a case where force applied to rigidbody. Rigidbody untouched in FixedUpdate() now.
    Code (CSharp):
    1. public void Test()
    2. {
    3.     _rigidbody.AddForce(this.transform.forward * _startSpeed * _rigidbody.mass, ForceMode.Impulse);
    4. }
    5. private void FixedUpdate() { }
    All rigidbodies set to be non kinematic and I tried to set different interpolation modes for them. Collision detection is still ContinuousDynamic.

    If any or both Ship and Shell are triggers this not working as well. But if they both have 'Is Trigger' unchecked the collision occurs. This is odd as to me.