Search Unity

Collision.GetContacts() gives inconsistent collision points?

Discussion in 'Physics' started by Creepuh_, Jun 15, 2019.

  1. Creepuh_

    Creepuh_

    Joined:
    Jul 30, 2014
    Posts:
    2
    Hi all. Been searching about this, and came up with nothing.

    Since collision.contacts should be avoided because GC, I use Collision.GetContacts to store collision points to check if my player is grounded. This returns some points that seem reasonable, while the rest of the array is filled with (0, 0, 0) even though the collision is very far away from the world origin. Sometimes, the collision points don't even make sense, like they are just in random positions. Can anyone help me with my code? Am I using GetContacts wrong (they don't have an example in the docs)?

    Code (CSharp):
    1.     void OnCollisionEnter(Collision collision)
    2.     {
    3.         TrackGround(collision);
    4.     }
    5.     void OnCollisionStay(Collision collision)
    6.     {
    7.         TrackGround(collision);
    8.     }
    9.     void OnCollisionExit(Collision collision)
    10.     {
    11.         TrackGround(collision);
    12.         grounded = false;
    13.     }
    14.  
    15.     void TrackGround(Collision col)
    16.     {
    17.         ContactPoint[] contacts = new ContactPoint[10];
    18.         col.GetContacts(contacts);
    19.         gHeight = capsuleCollider.bounds.min.y + capsuleCollider.radius * .9f;
    20.  
    21.             foreach (var contact in contacts) {
    22.  
    23.                 if (contact.point.y < gHeight) { // this returns true because when I jump-collide with the wall, contact.point.y == 0 (while I'm in the air) for some reason??
    24.                     grounded = true;
    25.                     break;
    26.                 }
    27.                 else {
    28.                     grounded = false;
    29.                     break;
    30.                 }
    31.  
    32.             }
    Or is this a bug?

    Any help is appreciated! Thank you
     
  2. First, move out the line
    Code (CSharp):
    1. ContactPoint[] contacts = new ContactPoint[10];
    from the TrackGround method. You're creating a new array on every collision. It doesn't make sense.
    Second, the GetContacts returns with an integer, which says how many contact points you get. So you can iterate only the first N member in your array to get all the valid contact points (if N = col.GetContacts(contacts)).
    Manual is here.
    Or you can use contacts as a List type so you don't have to worry about more or less contact points over time (slightly slower than an array).
    So instead of for(var contact in contacts) you should
    int noOfContacts = col.GetContacts(contacts);
    for(int i=0; i < noOfContacts; i++) {
    if (contacts.point.y < gHeight) ... etc
    }
     
    SateyrOfficial and Creepuh_ like this.
  3. Creepuh_

    Creepuh_

    Joined:
    Jul 30, 2014
    Posts:
    2
    Thanks very much! I still don't know why the array (or the list, I've tried) is populated with Vector3.zeros, but your for loop does the job well!
     
  4. Just think about what you're doing and what Unity is doing:
    - you create an array with 10 elements (all of them are Vector3.zero)
    - you ask Unity to give you N (let's say 3) collision points
    - Unity fill up the first N (3) elements with collision points and returns with N (3)
    - you have an array with 3 points and 7 Vector3.zero in your array

    but if next time Unity returns with only two points, you will have two new points, an old point and seven zeros in your array, this is why it is important to use the noOfContacts value in our example, otherwise you're reading old results, which is now garbage
     
    SmithySFC likes this.