Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Collision detected outside of the object

Discussion in 'Physics' started by igoapp, Sep 20, 2021.

  1. igoapp

    igoapp

    Joined:
    Aug 8, 2021
    Posts:
    20
    I have a fast moving object that should detect collision with the rectangular in the centre (a blast is seen). If the rectangular is not touched, no collision should be detected. The ball has a Rigidbody with collision detection of Continuous Dynamic. The rectangular and the wall have a Rigidbody with Continuous detection. I am using the following code:

    Code (CSharp):
    1. private void OnCollisionEnter(Collision collision)
    2. {
    3.         GetComponent<TrailRenderer>().enabled = false;
    4.  
    5.         if (collision.collider.tag == "Enemy")
    6.         {
    7.             GameObject expl = Instantiate(explosion, transform.position, Quaternion.identity) as GameObject;
    8.             Destroy(expl, 2);
    9.         }
    10. }
    The problem is that the collision is detected even when the ball hits the wall close to the rectangular. If it hits the wall far from the object, the collision is not detected (as it should). Based on what I have researched so far, the collision detection is not perfect with fast moving objects even when continuous detection is used. Is there any way to address this issue?

    Here is the video:
    https://drive.google.com/file/d/1AaDkZBlasgyZOG2lOKqznWdSm_Br8BvH/view?usp=sharing


    Thanks!
     
    Last edited: Sep 21, 2021
  2. r31o

    r31o

    Joined:
    Jul 29, 2021
    Posts:
    460
    Can you show the inspector?
     
  3. igoapp

    igoapp

    Joined:
    Aug 8, 2021
    Posts:
    20
    Attached. Thank you!
     

    Attached Files:

  4. r31o

    r31o

    Joined:
    Jul 29, 2021
    Posts:
    460
    I think that the error is in the enemy, it is in the water layer. Not sure, but I know the water layer has some specific attributes.
    Change it to another layer
    Also, if the wall doesnt move, it doesnt need a rigidbody.
     
  5. igoapp

    igoapp

    Joined:
    Aug 8, 2021
    Posts:
    20
    Thanks, @r31o, for the suggestion. Unfortunately, it does not help. Tried different layers, but still having the same problem.

    Also, it may be a placebo, but it looks like the faster the ball flies, the greater the distance is outside of the enemy boundary where collision is detected.
     
    Last edited: Sep 21, 2021
  6. r31o

    r31o

    Joined:
    Jul 29, 2021
    Posts:
    460
    I think maby will be CCC (continous collision detection), as it tries to predict where the ball will be, so, for the physics engine, "Is there" even if physicaly isint.
    Just try it. Maby it can solve your problem.
    If not (I hope that I solved the problem), put it here and I will try to figure out what happens. :p
     
  7. BakeMyCake

    BakeMyCake

    Joined:
    May 8, 2017
    Posts:
    175
    You could try ray casting the collider from it's origin to destination. This obviously only works for linear movement, but it's about as reliable as it gets. In my case I have objects that can reach 20 unity-units-per-second speed and this approach never betrayed me so far.

    The video you demonstrated kinda looks too wrong to be true. CCD has its' issues, but it's not this inaccurate. We can't help based on the provided information, but I suspect there is some error in your scene setup that you're missing, that makes this behaviour perfectly valid.

    Like for example your slingshot stone has a spherical model but you use a box collider for it? Visually the ball may not be touching the 'enemy', but the invisible box that you're using for collision detection probably is.

    You can investigate your problem by inserting a Debug.Break() call when the 'explosion' is spawned. Debug.Break() is the same as pressing pause in the editor. When the pause occurs, switch to the scene view and take a close look at the state of the scene and the hit boxes. Maybe even take a look at the physics debug view https://docs.unity3d.com/Manual/PhysicsDebugVisualization.html
     
  8. igoapp

    igoapp

    Joined:
    Aug 8, 2021
    Posts:
    20
    Thank you, @BakeMyCake. I have tried playing with Debug.Break(), and the results are attached. Here is a more complete script for the stone prefab:

    Code (CSharp):
    1. public class Stone : MonoBehaviour
    2. {
    3.     public Vector3 initPosition;
    4.     public Rigidbody Rb;
    5.     public GameObject explosion;
    6.     public float ReleaseTime = 0.1f;
    7.     public float DestructionTime = 2.0f;
    8.     private bool _isPressed;
    9.     private bool _isFired;
    10.     public float RbForceFactor = 2000;
    11.  
    12.  
    13.     private void Awake()
    14.     {
    15.         initPosition = transform.position;
    16.         Rb = GetComponent<Rigidbody>();
    17.     }
    18.  
    19.  
    20.     void FixedUpdate()
    21.     {
    22.         if (_isPressed && !_isFired && !GameManager.Instance.IsLevelCleared)
    23.         {
    24.             Vector3 mousePosition = Input.mousePosition;
    25.  
    26.             // Factors that affect the extent to which stone can be moved to the sides (depends on the resolution?)
    27.             float screenToWorldPoint_factor = 1f;
    28.      
    29.             // Stone is moved along the z-axis depending on moving the mouse along the Y-axis
    30.             float x2 = .... here goes a formula
    31.             float x1 = .... here goes a formula
    32.             float y2 = .... here goes a value
    33.             float y1 = .... here goes a value
    34.             float m = (y2 - y1) / (x2 - x1);
    35.             float b = .... here goes a value
    36.             float worldPosition_z = m * mousePosition.y - b;
    37.  
    38.             Vector3 worldPosition = Camera.main.ScreenToWorldPoint(new Vector3( mousePosition.x,
    39.                                                                                 screenToWorldPoint_factor,
    40.                                                                                 screenToWorldPoint_factor));
    41.  
    42.             worldPosition.y = 3.3f;
    43.             worldPosition.z = worldPosition_z;
    44.  
    45.             Rb.position = worldPosition;
    46.         }
    47.     }
    48.  
    49.  
    50.     void OnMouseDown()
    51.     {
    52.         if (_isFired || GameManager.Instance.IsLevelCleared)
    53.         {
    54.             return;
    55.         }
    56.  
    57.         _isPressed = true;
    58.         Rb.isKinematic = true;
    59.     }
    60.  
    61.  
    62.     void OnMouseUp()
    63.     {
    64.         if (_isFired || GameManager.Instance.IsLevelCleared)
    65.         {
    66.             return;
    67.         }
    68.  
    69.         _isPressed = false;
    70.         Rb.isKinematic = false;
    71.  
    72.         // Rigidbody Force
    73.         // Y-position of the initial position should equal Y-position of the transform position
    74.         // Otherwise, the stone will be flying higher
    75.         initPosition.y = transform.position.y;
    76.  
    77.         Vector3 directionToInitialPosition = initPosition - transform.position;
    78.         Rb.AddForce(directionToInitialPosition * RbForceFactor);
    79.  
    80.         Destroy(GetComponent<SpringJoint>());
    81.  
    82.         GetComponent<TrailRenderer>().enabled = true;
    83.         _isFired = true;
    84.         StartCoroutine(Release());
    85.     }
    86.  
    87.  
    88.     private void OnCollisionEnter(Collision collision)
    89.     {
    90.         GetComponent<TrailRenderer>().enabled = false;
    91.  
    92.         Debug.Log("Collider: " + collision.collider.name);
    93.  
    94.         // Explode on collision with the Enemy
    95.         if (collision.collider.tag == "Enemy")
    96.         {
    97.             Debug.Break();
    98.             GameObject expl = Instantiate(explosion, transform.position, Quaternion.identity) as GameObject;
    99.             Destroy(expl, 2); // delete the explosion after 2 seconds
    100.         }
    101.    
    102.     }
    103.  
    104.  
    105.     IEnumerator Release()
    106.     {
    107.         yield return new WaitForSeconds(ReleaseTime);
    108.         StartCoroutine(Explode());
    109.     }
    110.  
    111.  
    112.     IEnumerator Explode()
    113.     {
    114.         yield return new WaitForSeconds(DestructionTime);
    115.  
    116.         GameManager.Instance.SetNewStone();
    117.         Destroy(gameObject);
    118.     }
    119. }
    Thanks!

    EDIT: All the research I have done does refer me to collision ray casting. I am Googling now for the best way to implement it.
     

    Attached Files:

    Last edited: Sep 23, 2021
  9. igoapp

    igoapp

    Joined:
    Aug 8, 2021
    Posts:
    20
    While I am figuring how to do collision ray casting, I also wanted to show the video where the collision is happening frame by frame. This shows that collision is detected way outside of the applicable object.

     
  10. BakeMyCake

    BakeMyCake

    Joined:
    May 8, 2017
    Posts:
    175
    I've attempted to recreate this but couldn't in version 2020.3.6.
    If you wanna try it out I've attached my test scene, make sure you set the physics layers so that the balls don't collide with each other.

    For me it looks like in the gif below:
    Collision2.gif

    I don't know what else to suggest other than maybe start checking every single setting you have to see what breaks it.
     

    Attached Files:

  11. igoapp

    igoapp

    Joined:
    Aug 8, 2021
    Posts:
    20
    Thank you so much, @BakeMyCake ! I will try it and report on the outcome.
     
  12. igoapp

    igoapp

    Joined:
    Aug 8, 2021
    Posts:
    20
    @BakeMyCake and @r31o .

    I believe I have found the culprit. It is in this code:

    Code (CSharp):
    1. void OnMouseDown()
    2. {
    3.         if (_isFired || GameManager.Instance.IsLevelCleared)
    4.         {
    5.             return;
    6.         }
    7.  
    8.         _isPressed = true;
    9.         //Rb.isKinematic = true; THIS IS THE CULPRIT!!!
    10. }
    For me to be able to pull the stone imitating a slingshot, I was trying to make the ball's rigidbody kinematic. If I remove this line, collision is detected properly. But in this case, I cannot pull the stone -- it jitters then. If I keep the line, problems with collision occur.

    In my opinion, this does not make any sense. Could anyone please explain why this may be even happening and how I could address it?

    Thanks a lot!

     
    Last edited: Sep 26, 2021
    Ajasmm02 likes this.
  13. talhaacikel3

    talhaacikel3

    Joined:
    Mar 25, 2021
    Posts:
    1
    I don't know if your project and error still persist but i think i found both problem and solution. I am writing for people who have same problem and googleing. For me the solution was: Go to: Edit > Project Settings > Physics and check the Default Contact Offset if the number there is 1 or greater change it to a lower value. I think it is in meters so something like 0.01 (1cm) should be fine.