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

Can't get the contacts from multiple collisions.

Discussion in 'Physics' started by Relan42, May 15, 2022.

  1. Relan42

    Relan42

    Joined:
    Nov 2, 2017
    Posts:
    2
    I'm using contact normals to detect when the player is grounded. It works perfectly except for when I touch a wall before touching the ground. The problem seems to be that it only takes the contacts from the earliest collison. Is there a way of getting the contacts from all collisions?

    Here's the code I'm using to detect if something is grounded.

    Code (CSharp):
    1.    private ContactPoint2D[] contacts;
    2.    private Collision2D collision1;
    3.  
    4. void Update()
    5. {
    6. if (contacts != null && collision1 != null && rb.GetContacts(contacts) > 0)
    7.         {
    8.  
    9.             //For detecting the ground
    10.             foreach (ContactPoint2D contact in contacts)
    11.             {
    12.                 if (contact.normal == new Vector2(0, 1))
    13.                 {
    14.                     isGrounded = true;
    15.                     break;
    16.                 }
    17.                 else
    18.                 {
    19.                     isGrounded = false;
    20.                 }
    21.             }
    22.  
    23.             if (rb.GetContacts(contacts) == 0)
    24.             {
    25.                 isGrounded = false;
    26.             }
    27.                 }
    28.  
    29.                 for (int i = 0; i < rb.GetContacts(contacts); i++)
    30.                 {
    31.                     if (collision1.GetContact(i).normal == new Vector2(-1, 0))
    32.                     {
    33.                         if (collision1.transform.CompareTag("Right One Way Wall") == false && xVelocity >= 0)
    34.                         {
    35.                             touchesRightWall = true;
    36.                             break;
    37.                         }
    38.                     }
    39.                     else
    40.                     {
    41.                         touchesRightWall = false;
    42.                     }
    43.                 }
    44.             }
    45.         }
    46. }
    47.  
    48.     private void OnCollisionStay2D(Collision2D collision)
    49.     {
    50.         contacts = collision.contacts;
    51.         collision1 = collision;
    52.         for (int i = 0; i < rb.GetContacts(contacts); i++)
    53.         {
    54.             Debug.DrawRay(collision.GetContact(i).point, collision.GetContact(i).normal, Color.red);
    55.         }
    56.  
    57.     }
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,326
    That's not true. When you ask for contacts, you get all the current contacts. You don't get contacts that have stopped being contacts i.e. they are no longer in contact; it's not a contact history.

    Also note, you're reading this in update but contacts are not updated until the simulation runs which (by default) isn't per-frame.

    There's a far easier and faster way to do this using Rigidbody2D.IsTouching in conbination with a simple ContactFilter2D. You can also expose the filter to the Inspector to configure it there rather than code too.

    You can see it being used here to determine grounded state. You can use multiple ones too if you wish. Note that this links to my physics examples project:


    Ultimately, in the example, the grounded check is a simple single line: https://github.com/Unity-Technologi...Miscellaneous/SimpleGroundedController.cs#L17

    Final note: You're reading the Rigidbody2D.GetContacts but you're already provided those in the physics callbacks: https://docs.unity3d.com/ScriptReference/Collision2D.html