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. Dismiss Notice

Bug A weird collision bug

Discussion in 'Physics' started by The_wARmAcH1n3, Oct 10, 2023.

  1. The_wARmAcH1n3

    The_wARmAcH1n3

    Joined:
    Aug 5, 2023
    Posts:
    27
    I made an enemy in 2d with Box2d Collision. Additional I define with code areas to check if the enemy touch the ground, wall and if the area above is free for jumping. Now I have a weird collision bug, which comes rarely, that the soldier is hanging in the air endless in jumping phase at the edge if the ground/wall. I thought, that the collision of the enemy and the ground/wall is touching but the check with the touching to the ground fails. So paused the game and zoomed very near in and see that the collision of the enemy and the ground aren't even touching! I don't know how clear this bug.

    My code:
    Code (CSharp):
    1.     protected override void CheckWallCollision()
    2.     {
    3.  
    4.         m_onJumpLeftWall = false;
    5.         m_onJumpRightWall = false;
    6.  
    7.         colliderWall = Physics2D.OverlapBox((Vector2)groundCheck.position, groundCollisionSize, 0.0f, whatIsGround);
    8.         if (colliderWall != null)
    9.         {
    10.             isGrounded = true;
    11.             timerFalling = 0f;
    12.             //isJumping = false;
    13.         }
    14.         else
    15.         {
    16.             isGrounded = false;
    17.             timerFalling += Time.deltaTime;
    18.         }
    19.            
    20.  
    21.         // check if on wall
    22.         colliderWall = Physics2D.OverlapBox(objectPosition + wallRightOffset, wallCollisionSize, 0.0f, whatIsGround);
    23.         if (colliderWall != null)
    24.             m_onRightWall = true;
    25.         else
    26.             m_onRightWall = false;
    27.  
    28.         colliderWall = Physics2D.OverlapBox(objectPosition + wallLeftOffset, wallCollisionSize, 0.0f, whatIsGround);
    29.         if (colliderWall != null)
    30.             m_onLeftWall = true;
    31.         else
    32.             m_onLeftWall = false;
    33.  
    34.         if (m_facingRight)
    35.         {
    36.             if (m_onRightWall)
    37.             {
    38.                 colliderWall = Physics2D.OverlapBox(objectPosition + wallJumpRightOffset, wallCollisionSize, 0.0f, whatIsGround);
    39.                 if (colliderWall == null || isJumping)
    40.                 {
    41.                     m_onJumpRightWall = true;
    42.                     //Debug.Log("m_onJumpRightWall = true;   isJumping = " + isJumping);
    43.                 }
    44.                 else
    45.                 {
    46.                     m_onJumpRightWall = false;
    47.                     if ((m_rb.velocity.y > 0f) == false && isGrounded)
    48.                     {
    49.                         //Debug.Log("RIGHT Flip  isJumping = " + isJumping + "  m_rb.velocity.y=" + m_rb.velocity.y + "m_facingRight =" + m_facingRight + "  isGround=" + isGrounded + "  isShooting=" + isShooting + "  leftWall=" + m_onLeftWall + "  leftJump=" + m_onJumpLeftWall + "  right=" + m_onRightWall + "  rightJump=" + m_onJumpRightWall);
    50.                         FlipL();
    51.                     }
    52.                 }
    53.             }
    54.         }
    55.         else
    56.         {
    57.             if (m_onLeftWall)
    58.             {
    59.                 colliderWall = Physics2D.OverlapBox(objectPosition + wallJumpLeftOffset, wallCollisionSize, 0.0f, whatIsGround);
    60.                 if (colliderWall == null || isJumping)
    61.                 {
    62.                     m_onJumpLeftWall = true;
    63.                     //Debug.Log("m_onJumpLeftWall = true;    isJumping = " + isJumping);
    64.                 }
    65.                 else
    66.                 {
    67.                     m_onJumpLeftWall = false;
    68.                     if ((m_rb.velocity.y > 0f) == false && isGrounded)
    69.                     {
    70.                         //Debug.Log("LEFT Flip  isJumping = " + isJumping + "m_rb.velocity.y=" + m_rb.velocity.y + "m_facingRight=" + m_facingRight + "  isGround=" + isGrounded + "  isShooting=" + isShooting + "  leftWall=" + m_onLeftWall + "  leftJump=" + m_onJumpLeftWall + "  right=" + m_onRightWall + "  rightJump=" + m_onJumpRightWall);
    71.                         FlipR();
    72.                     }
    73.                 }
    74.             }
    75.         }
    76.     }
    77.  
     

    Attached Files:

  2. JustinNaicker

    JustinNaicker

    Joined:
    Jan 4, 2023
    Posts:
    47
    Had this exact issue before. What I had done was assign a new physics material on the tiles on the far left and right and add 0 friction to the physics material so the player would slide off.

    You could also use a CircleCollider for the entire player (or a CircleCollider for the lower half and BoxCollider for the top half) to prevent this issue.
     
  3. The_wARmAcH1n3

    The_wARmAcH1n3

    Joined:
    Aug 5, 2023
    Posts:
    27
    After some test it seems that if I set FixedUpdate-timestep to 200fps the bug occurs more often, if I set the timestep to 50 fps the bug doesn't occur.
     
  4. The_wARmAcH1n3

    The_wARmAcH1n3

    Joined:
    Aug 5, 2023
    Posts:
    27
    This is wrong, error occurs with 50 fps too.
     
  5. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,529
    A much better and 100% accurate approach is to simply use the existing contacts to determine what you are in contact with. This is what the physics system responds to. No need to construct queries with sizes of colliders, position them etc. You can filter contacts by normal direction, layer etc.



    When you have your ContactFilter2D set-up for each thing you want to detect i.e. ground from below, walls to the left/right etc then a query is a simple as: https://github.com/Unity-Technologi...Miscellaneous/SimpleGroundedController.cs#L17
     
  6. The_wARmAcH1n3

    The_wARmAcH1n3

    Joined:
    Aug 5, 2023
    Posts:
    27
    I have set a physic material with Friction = 0 and Bounciness = 0 at the box collider 2D of the enemy and it seems to work! After one hour testing the bug don't occur! Thanks!
     
  7. The_wARmAcH1n3

    The_wARmAcH1n3

    Joined:
    Aug 5, 2023
    Posts:
    27
    After using the physic material it seems to work great. I learnt this technic with this kit and used the controller-script as a base for the enemies:
    https://assetstore.unity.com/packag...mer-controller-with-animated-character-245475

    I'm new to Unity-devolping and this kit was a good start for me.

    What I don't know exactly:
    By a collision there comes an array of ContactPoint2D, how to know with ContactPoint of the array is the important one? I don't understand why I get more ContactPoint2D as only one single because I only check the tilemap for the overlaping check.

    I use this code:

    Code (CSharp):
    1.         colliderWall = Physics2D.OverlapBox((Vector2)groundCheck.position, groundCollisionSize, 0.0f, whatIsGround);
    2.         if (colliderWall != null)
    3.         {
    4.             int contactsCounts = colliderWall.GetContacts(collidersArray);
    5.             for (int i = 0; i < contactsCounts; i++)
    6.             {
    7.                 if (collidersArray[i].normal.y <= -0.98)
    8.                 {
    9.                     if (!isGrounded)
    10.                     {
    11.                         if (Random.value > 0.5f && !isFliped && timerFalling > 0.59f)
    12.                         {
    13.                             Debug.Log("timerFalling Flip  isJumping = " + isJumping + "  m_rb.velocity.y=" + m_rb.velocity.y + "m_facingRight =" + m_facingRight + "  isGround=" + isGrounded + "  isShooting=" + isShooting + "  leftWall=" + m_onLeftWall + "  leftJump=" + m_onJumpLeftWall + "  right=" + m_onRightWall + "  rightJump=" + m_onJumpRightWall);
    14.                             Debug.Log(timerFalling);
    15.                             Flip();
    16.                         }
    17.                     }
    18.                     //Debug.Log("y==-1" + collidersArray[0].normal);
    19.                     isGrounded = true;
    20.                     timerFalling = 0f;
    21.                     break;
    22.                 }
    23.             }
    24.         }
    25.         else
    26.         {
    27.             isGrounded = false;
    28.             if((m_rb.velocity.y > 0.001f) == false)
    29.             {
    30.                 timerFalling += Time.deltaTime;
    31.             }
    32.         }
    33.  
     
    Last edited: Oct 11, 2023
  8. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,529
    I don't understand the question. What you're doing above is quite advanced if you don't already understand the basics so there's going to be a lot of confusion here.

    I don't understand why you do an overlap box first when you can just ask for the contacts or use IsTouching on a specific layer as I've already mentioned above.

    All fo the following:
    Code (CSharp):
    1.         colliderWall = Physics2D.OverlapBox((Vector2)groundCheck.position, groundCollisionSize, 0.0f, whatIsGround);
    2.         if (colliderWall != null)
    3.         {
    4.             int contactsCounts = colliderWall.GetContacts(collidersArray);
    5.             for (int i = 0; i < contactsCounts; i++)
    6.             {
    7.                 if (collidersArray[i].normal.y <= -0.98)
    Can be reduced to the single line I demonstrated above but you've bypassed and are going for a much more complex and fragile approach.

    Code (CSharp):
    1. public ContactFilter2D ContactFiler;
    2.  
    3. public bool IsGrounded => m_Rigidbody.IsTouching(ContactFilter);
    ... and just configure the ContactFilter2D in the inspector so that you're only interested in a contact normal pointing up (the ground) and specific layer(s).
     
  9. The_wARmAcH1n3

    The_wARmAcH1n3

    Joined:
    Aug 5, 2023
    Posts:
    27
    Thanks, I will look at this and try it out.
     
  10. The_wARmAcH1n3

    The_wARmAcH1n3

    Joined:
    Aug 5, 2023
    Posts:
    27
    I tried it and it works well!
     
  11. The_wARmAcH1n3

    The_wARmAcH1n3

    Joined:
    Aug 5, 2023
    Posts:
    27
    I made a public ContactFilter2D and in the editor there is a Min Normal Angle and a Max Normal Angle. But is this x normal angle or y normal angle? How can I differentiate between x and y by the Normal Angle in the ContactFilter?
     
  12. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,529
    A single value in a Vector2 isn't an angle, it's just a scalar value. Only the two combined give you an angle.

    Vector2.right (1, 0) is zero.
    Vector2.up (0, 1) is +90 (or -270)
    Vector2.left (-1, 0) is +180 (or -180)
    Vector2.down (0, -1) is +270 (or -90)

    Code (CSharp):
    1. collidersArray[i].normal.y <= -0.98
    I can sort of see where you get the idea to only use the vertical component of the normal even though I don't understand why you're using -0.98. A normal from the ground would be upwards so (0,1) i.e. "< 0.98".

    If you were to look at the demo I linked, you'd see how it worked. An upwards normal from the ground is +90 but if you also want small deviations from that then use +/- however many degrees you want. For instance, if you want a 20-deg spread then you could use +80 to +100 degrees.

    The angle from a Vector2 normal is calculated using:
    Code (CSharp):
    1. float normalAngle = Mathf.Atan2(normal.y, normal.x) * Mathf.Rad2Deg;
    Hope this helps.
     
  13. The_wARmAcH1n3

    The_wARmAcH1n3

    Joined:
    Aug 5, 2023
    Posts:
    27
    Thank you very much, now I understand it with the angle.
     
    MelvMay likes this.
  14. The_wARmAcH1n3

    The_wARmAcH1n3

    Joined:
    Aug 5, 2023
    Posts:
    27
    I have a problem with the ContactFilter. I use the ContactFilter2D with normal angles to check which angle have the ground so that the monster rotate in same angle, see this video:



    This works well but when I made my monster falling from the top my problem is that I get false positive on landing the ground by 45° and 315° ContactFilter. The monster have a capsule collider 2d and if the monster touch the ground at some edge like in the picture the contactfilter with normal angle from 134° to 136° (for 45° diagonal ground) it gives me false positive and the monster rotates in wrong angle.

    How can I correct the false positive?

    My code:
    Code (CSharp):
    1. m_onBottomWall = m_rb.IsTouching(ContactFilterBottom);
    2.  
    3. m_onBottomRightWallFall = m_rb.IsTouching(ContactFilterBottomRightFall);
    4. m_onBottomLeftWallFall = m_rb.IsTouching(ContactFilterBottomLeftFall);
    5.  
    6. if (isFalling && RotatingFirstStep && (m_onBottomWall || m_onBottomLeftWallFall || m_onBottomRightWallFall))
    7. {
    8.     MakeNotFalling();
    9.     Debug.Log("MakeNotFalling  " + "   m_onBottomWall " + m_onBottomWall + "   m_onBottomLeftWallFall " + m_onBottomLeftWallFall + "  m_onBottomRightWallFall " + m_onBottomRightWallFall + "  rotationAngle " + rotationAngle);
    10.     if (m_onBottomWall)
    11.         Rotate(0, false);
    12.     else if (m_onBottomLeftWallFall)
    13.     {
    14.         Rotate(315, false);
    15.         Debug.Log("Rotate(315, false)");
    16.     }
    17.     else if (m_onBottomRightWallFall)
    18.     {
    19.         Rotate(45, false);
    20.         Debug.Log("Rotate(45, false)");
    21.     }
    22.  
     

    Attached Files: