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

Question How to do the the same SweepTest from Rigidbody in Rigidbody2D ?

Discussion in '2D' started by ihorBandura, Jun 26, 2023.

  1. ihorBandura

    ihorBandura

    Joined:
    Jul 11, 2021
    Posts:
    3
    Hello Everyone !

    I have experience in programming, but I'm a beginner in Unity, so sorry if I ask some dumb things:oops:

    I have a legacy project where 3D Physics was used for 2D game. And now I need to copy that Character Controller code and rewrite it for 2D Physic. Everything was fine till I faced SweepTest method.

    I tried to write that method on my own using Rigidbody.Cast or Raycasts, but nothing helps :(

    My character keeps falling from the edges(it must be on the ground all the time with slopes) and doesn't see walls correctly (so magnets to a wall, wall sliding, and wall jumping s**k too).

    If I understood correctly SweepTest was used there to check left\right walls, ceiling, and ground. Velocity calculates based on those hits(for example, if we have hit to a wall -> we can calculate velocity to
    magnetize character to that wall).

    With 3D Physic everything works perfectly but with 2D and my versions of SweepTest it keeps failing on ground, failing from edges and everything I described later.

    Thank you in advance :)

    Here are some examples of my tries to recreate SweepTest for 2D(I have only one CapsuleCollider on my gameobject):

    with Cast:
    Code (CSharp):
    1. public static bool SweepTest(this Rigidbody2D rb2D, Vector2 direction, float distance, out RaycastHit2D result)
    2.         {
    3.             var hits = new List<RaycastHit2D>();
    4.             rb2D.Cast(direction, hits, distance);
    5.  
    6.             var attachedColliders = new List<Collider2D>();
    7.             rb2D.GetAttachedColliders(attachedColliders);
    8.            
    9.             foreach (var hit in hits)
    10.             {
    11.                 if (hit.collider.isTrigger)
    12.                     continue;
    13.                
    14.                 foreach (var attachedCollider in attachedColliders)
    15.                 {
    16.                     if (attachedCollider != hit.collider)
    17.                     {
    18.                         result = hit;
    19.                         return true;
    20.                     }
    21.                 }
    22.             }
    23.  
    24.             result = default;
    25.             return false;
    26. }
    With Raycast:
    Code (CSharp):
    1. public static bool SweepTestRaycast(this Rigidbody2D rb2D, Vector2 direction, float distance, out RaycastHit2D result)
    2.         {
    3.             var attachedColliders = new List<Collider2D>();
    4.             rb2D.GetAttachedColliders(attachedColliders);
    5.             foreach (var attachedCollider in attachedColliders)
    6.             {
    7.                 var mesh = attachedCollider.CreateMesh(true, true);
    8.                 foreach (var vertice in mesh.vertices)
    9.                 {
    10.                     Debug.DrawRay(vertice, direction, Color.red);
    11.                     result = Physics2D.Raycast(vertice, direction, distance);
    12.                    
    13.                     if (result != null && result != (default) && result.collider != null)
    14.                     {
    15.                         var continueCheckForCollide = false;
    16.                         foreach (var attachedColliderToCheck in attachedColliders)
    17.                         {
    18.                             if (result.collider == attachedColliderToCheck)
    19.                             {
    20.                                 continueCheckForCollide = true;
    21.                                 break;
    22.                             }
    23.                         }
    24.            
    25.                         if (!continueCheckForCollide)
    26.                         {
    27.                             return true;
    28.                         }
    29.                     }
    30.                 }
    31.             }
    32.            
    33.             result = default;
    34.             return false;
    35. }
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    Rigidbody2D.Cast already ignores the colliders attached to the Rigidbody2D. Also, use a ContactFilter2D to filter out triggers (or anything else you're not interested in). Finally, don't create a list then throw it away to the GC, reuse it as that's the whole point of being able to pass arrays/lists i.e. improving performance and not putting pressure on the GC.

    Sorry but the raycast version is absolutely awful. You're creating mesh asset each time it's called. Why would you do this? Raycasting from every single vertex in a mesh isn't scalable. :)
     
    ihorBandura likes this.
  3. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    Also note that unlike 3D physics, 2D physics sorts results so if you ask for a single result, it'll be the first hit you encountered too or in the case of above the first entry in the list is the first hit.

    Roughly this but consider reusing the array:
    Code (CSharp):
    1. public static bool SweepTest(this Rigidbody2D rb2D, Vector2 direction, float distance, out RaycastHit2D result)
    2. {
    3.     var hit = new RaycastHit2D[1];
    4.     var resultCount = rb2D.Cast(direction, new ContactFilter2D(), hit, distance);
    5.     result = hit[0]
    6.     return resultCount > 0;
    7. }
     
    ihorBandura likes this.
  4. ihorBandura

    ihorBandura

    Joined:
    Jul 11, 2021
    Posts:
    3
    Yeaaaah) it's very awful:D This thing just drives me crazy:) I spent almost 3 weeks on this. It's not for Prod, so I simply tried multiple things and that was my last monster with the Raycast approach. I didn't want to do something similar with Cast, so came here for help:D
     
  5. ihorBandura

    ihorBandura

    Joined:
    Jul 11, 2021
    Posts:
    3
    Thank you very much :)
    At least now I know in which direction I need to go to find that little radiance at the end of the tunnel :D

    Again thank you;)
     
  6. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    10,468
    No problem at all. Nothing I've seen in the code above would describe the problem you mentioned though so maybe there's something else wrong in the logic. I know what it's like to sometimes not be able to see the "wood for the trees" so thought I'd mention it.