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

Ray-casting corners

Discussion in 'Scripting' started by Michael_93, May 23, 2016.

  1. Michael_93

    Michael_93

    Joined:
    Jan 12, 2014
    Posts:
    95
    I am doing a 2d plat former and I am using raycasts for collision detection. I am currently trying to fix an issue with angled corners. Originally I would have 5 rays test the x axis for collision but this becomes a problem with corners because the ray doesn't realize that there is an object in front. This is most noticeable when the player is moving horizontally and vertically.

    So I decided to use a lot of rays instead which "fixes" the problem My question is will this cause a significant decrease in performance? If so does anyone know a better method to approach this problem
     

    Attached Files:

  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Can you do a capsule cast instead of a ray cast? Sort of looks like what you're going for anway
     
  3. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
  4. Michael_93

    Michael_93

    Joined:
    Jan 12, 2014
    Posts:
    95
    Well since I'm using the 2d engine circle cast would be the only possible option. But why would I want to use a circle cast. My current method is along the lines of if the ray returns true it will snap the player next to the wall, I'm not sure if a circle cast would reliable for this.

    Also I should note I'm not using rigid bodies at all.
    Here is a snippet of my code
    Code (CSharp):
    1.  for (int i = 0; i < horiRayCount; i++)
    2.             {
    3.                 rayOrigin = originalOrigin + (Vector2.up * (horiRaySpaceing * i));
    4.                 hit = Physics2D.Raycast(rayOrigin, direction * Vector2.right,
    5.                     actualLength + skinWidth, collisionMask);
    6.                 if (hit.distance != 0 && hit.distance < rayLegnth && hit.collider != null && hit.collider.tag == platformTag)
    7.                 {
    8.                     actualLength = (hit.distance-skinWidth) * Time.deltaTime;
    9.                     rayLegnth = hit.distance;
    10.                     collision = true;
    11.                 }
    12.                 if (i == 0 && collision)//check for steping
    13.                 {
    14.                     //testing current problem without this add this later
    15.                     step = upStep(hit.distance, horiRaySpaceing, horiRayCount, direction, originalOrigin, skinWidth, collisionMask, platformTag);
    16.                    if (step) { speed.x = speed.y = 0.0F; return; }
    17.                 }
    18.  
    19.                Debug.DrawRay(rayOrigin, Vector2.right *direction* actualLength, Color.red);
    20.             }
    21.             if (collision)
    22.             {
    23.                 Debug.Log("horizontal collision");
    24.  
    25.                 transform.Translate(direction * (rayLegnth - skinWidth ), 0, 0);
     
  5. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    At the very least you could early-out of the loop when you hit something
    Code (csharp):
    1.  
    2. int i = 0;
    3. while (!collision && i < horiRayCount)
    4. {
    5.   // do your thing
    6.   i++;
    7. }
    8.  
     
  6. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    There's more than just circle cast. Checkout the entire Physics2D documentation:
    http://docs.unity3d.com/ScriptReference/Physics2D

    There's BoxCast, BoxcastAll, BoxCastNonAlloc, LineCast, OverlapArea, etc... I'm guessing you want to use BoxCast. I just said CircleCast as an example since I wasn't sure your exact use case.

    You should just be able to replace that entire for loop with a single Boxcast. I haven't gone line-by-line, but something like this.
    Code (csharp):
    1. Vector3 endCastPosition = originalOrigin + (ActualLength + skinWidth) * Vector2.right;
    2. RaycastHit2D hit = Physics2D.BoxCast(originalOrigin, endCastPosition, collisionMask;
    3. if (hit != null)
    4. {
    5.   actualLength = hit.distance - skinWidth;
    6.   castLength = hit.distance;
    7.   collision = true;
    8. }
     
  7. Michael_93

    Michael_93

    Joined:
    Jan 12, 2014
    Posts:
    95
    can't do that it can cause problems if the first thing you hit is farther than something else above
     
  8. Michael_93

    Michael_93

    Joined:
    Jan 12, 2014
    Posts:
    95
    Thank you for the help but I don't think that will work well enough. From what I can understand it will return true if there is a collision with another collider. However I imagine it will cause problems if it overlaps multiple shapes at different heights and x axis positions at once.
    I am by no means a pro but I doubt the box cast was made with this problem in mind
     
  9. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    It returns a RaycastHit2D with information about the collision. Or null if there is no collision.

    If you're worried about multiple colliders, you can BoxCastAll and get all the colliders with all their different hit points.
    http://docs.unity3d.com/ScriptReference/Physics2D.BoxCastAll.html

    Is there something I'm missing about what you need?
     
  10. Michael_93

    Michael_93

    Joined:
    Jan 12, 2014
    Posts:
    95
    I guess I'll give it a try for today.

    Just one last question if the box collider overlaps multiple objects at once what will happen? Will it return the point that is closest in the x direction.
    I guess I'm just having some trouble understanding the specifics on the box cast, guess I'll just do some testing best way for me to understand.

    Thanks for all the help by the way
     
  11. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    If you do box cast all, it will keep going even after the first hit. As it goes it tracks what colliders it is hitting, where the cast hit the collider, then returns an array filled with RaycastHit2D with all the hit points.

    I believe it'll return one RaycastHit2D per collider that the boxcast comes across. Documentation even says it's sorted by distance.
     
  12. GarthSmith

    GarthSmith

    Joined:
    Apr 26, 2012
    Posts:
    1,240
    Not exactly sure what you are asking, I believe if the box is already overlapping when you do the boxcast, then it won't detect anything it is already overlapping. You might be able to use OverlapBox but I don't think it's rotatable.
    http://docs.unity3d.com/ScriptReference/Physics2D.OverlapArea.html

    So the boxcast shouldn't be doing any overlapping. I believe it should return contact points. I would need to do some testing to see exactly how this works out (say dropping a flat box on flat surface. I have no idea what would be picked for the contact point.)
     
  13. Michael_93

    Michael_93

    Joined:
    Jan 12, 2014
    Posts:
    95
    Well I would like to thank you for the help with a different method but I just realized that I had a brain fart and all it took were two easy fixes.
    The first was setting up an if statement if there is a collision
    The second was the fact that I was dumb and multiplied actual ray length by time when I shouldn't have.
    So it works fine and I'm happy with it.
     
    GarthSmith likes this.