Search Unity

2D Circle/CapsuleCast point and distance values are incorrect

Discussion in 'Physics' started by SmittyA, Feb 6, 2019.

  1. SmittyA

    SmittyA

    Joined:
    May 21, 2013
    Posts:
    5
    I've been trying to write a 2D kinematic character controller for fun, using Physics2D.CapsuleCastNonAlloc, but I've been getting what appear to be incorrect point and distance values, and I've been trying to make sense of what's going on. I have a simple test environment with the origin of the cast at 0,0, with a radius of 0.5, and a box collider in the scene at 0,-2, with a height of 1. The cast's direction is down.



    Casting down, I get a RaycastHit2D.point of -1.4975 on the Y which is obviously a tad higher than the actual edge of the box collider (-1.5) - an offset of 0.0025, which has been consistent no matter what size or distance adjustments I make on the circle or box. To test further, I moved the circle to 0,-1, where it's radius would line up with the box's edge at -1.5, seen below with the two green lines.



    Even still, I get a point of -1.4975 (shown by the red line in the picture above where the upper circle and lower box intersect). Even stranger is that the RaycastHit2D.distance is 0.004950047, which doesn't line up with the perceived offset from the point, so I know where where the numbers are coming from, even accounting for floating point precision/rounding errors. I would expect the distance to be 0, but the distance that I calculate myself between the raycast point and the edge of my circle never matches the distance returned by the hit itself.

    I'm not sure if I'm just misunderstanding a fundamental part of Physics2D, or 2D casts, but I've done the same test with all types of 2D casts and get the same unexpected result. However, 2D raycasts work great and I get the exact values I expected. And performing the test with 3D Sphere/Capsule casts against a 3D collider returns exactly what I'm looking for (a hit detected at exactly 0,-1.5), so it's just 2D casts that are giving me grief. i've tested in 2018.3 and as far back as 5.6 to make sure it wasn't just a bug. I'm really hoping someone can explain what's going on.
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,481
    This is the contact offset and is a vital requirement for stable collision detection and is controlled by this property. At typical scales this should be visually insignificant as 0.0025m is only 2.5mm! Whilst you may be tempted to set this to zero, know that this can have a significant effect on collision detection so change it with caution.

    Hope this helps.
     
  3. SmittyA

    SmittyA

    Joined:
    May 21, 2013
    Posts:
    5
    That does make sense, thank you! What would the ideal workaround be for this in a character controller, because currently when my "character's" edge is up against the platform's edge (a real distance of 0, seen in the above image), the capsule cast call returns a distance of 0.004950047, meaning that the controller thinks it has room to move forward - this eventually leads the next frame's cast to think there's nothing there as the capsule is overlapping. Is it enough to simply subtract 0.005 to ensure I don't move beyond the edge? Or do I need to instead rely on manual overlap checks after moving, to keep me from going too far? Thanks again!
     
  4. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    I'm making a 2D platformer (https://forum.unity.com/threads/spelunky-clone-open-source-2d-platformer.935966/#post-6172939) and I'm currently using raycasts for a custom character controller, but I've recently spent quite a few hours investigating using Collider2D.Cast, Rigidbody2D.Cast, Physics2D.BoxCast and Collider2D.OverlapCollider instead of my raycasts because I felt that would be easier to work with, easier to understand and it wouldn't be possible for thin objects to pass through my array of raycasts the way that could happen now. And for all I know performance would be better as well.

    BUT all of the above methods give me the wrong distances / gaps, which I find unacceptable. And based on your reply and my own investigation they all rely on the contact offset setting and this setting is the source of this distance error. And it's not possible to set this value to 0 as you suggest, and even when you start approaching 0 everything starts failing.

    My current raycasts give me pixel perfect distances and therefore pixel perfect collisions. If a platform is at 32.0 height then my player will be at 32.0 height when standing on it. If a wall is on 16.0 x position then my player will be at 16.0 x position when moving against it. Using any of the above methods I will get decimals for every collision. Why does Physics2D.RayCast behave differently from the above methods? I can set the contact offset to 1 or 0.0001 and it's clear it doesn't affect Physics2D.RayCast or my current collision handling in any way whatsoever, but as soon as I use any of the above methods for attempting to handle my collisions then contact offset plays an essential part and it's impossible for me to get precise distances and therefore precise collision handling.

    I understand contact offset playing a part in the actual 2D physics system collision handling, but why is it interfering with me creating my own collision system using the above methods solely for finding the distances/overlaps needed to handle the collisions myself?

    And is there any workarounds? (apart from continuing to just use raycasts as I am currently doing obviously...)

    PS: I'm sorry if this is viewed as "necroing" an old thread. Since I still have this exact same question, nothing seems to have changed since this question was asked from what I can tell and there's an official reply here that I don't understand / don't agree with I feel this is as good a place as any to ask again.
     
  5. SmittyA

    SmittyA

    Joined:
    May 21, 2013
    Posts:
    5
    Since you replied, the contact offset has played no role in me fixing this issue, unfortunately. No amount of playing with the settings changed the distance I was getting with a perfectly overlapped surface. With normal raycasts I get a perfect distance of 0 when two edges overlap, but with a 2D cast I consistently get a super small distance (0.004950047) which may not sound like much, but that meant the system saw room to move, and would then move into the surface I'm supposed to be hitting.

    It's a terrible solution, but I ended up subtracting the exact offset I was seeing from all my casting checks, and it "worked". But I couldn't live with that solution because who knows how it would react on different systems/devices, so I opted to use 3D physics in a 2D world and have had no further issues.

    Would love to know what's actually going on because normal raycasting has zero distance issues.
     
  6. TwiiK

    TwiiK

    Joined:
    Oct 23, 2007
    Posts:
    1,729
    I don't remember exactly in what order I was testing the various methods and how thoroughly I tested each of them with various contact offsets, but I feel like Physics2D.BoxCast gave me the smallest gap and that was 0.005 fairly consistently, which seems to align with what you're saying. But I feel like setting contact offset to 0.0001 also made the BoxCast collision detection stop working. That was the last method I tested and at that point I just deleted everything I was experimenting with and returned to the raycasts I already had, which I knew worked.

    But I'm fairly certain that with all the casts that are based on the colliders attached to game objects that the distances became smaller the smaller I set the contact offset, but it never got to 0 and the closer I set contact offset to 0 the less reliable my movement system and collision handling became, maybe due to larger variances in the distances returned or for similar reasons as to why BoxCast also started failing even though contact offset didn't change the returned distance.

    Either way like I said it makes no sense to me that these methods which are essentially just "thick" raycasts don't return precise (read: correct) distances so that they can easily be used for making your own collision system when ordinary raycasts do. If contact offset and other physics related values are needed for the 2D physics system to work then they should apply later in the process, like for resolving collisions when rigidbodies are actually colliding or something, not so early that they interfere with the result returned from these methods. Either that or we should get "raw" versions of these methods or something where the physics system doesn't interfere with what we're trying to achieve. Reading the documentation you'd assume the only difference between Physics2D.RayCast and Physics2D.BoxCast was that one is a ray the width of a point while the other is a ray the size of a box, but clearly the physics system is interfering with BoxCast when it's not with RayCast.

    Edit: In 2D in general the idea of a boxcast or circlecast or capsulecast doesn't really make sense to me to begin with. Shouldn't it just be a width modifier for a raycast? If we're looking at either of these from a 2d perspective they are all just lines anyway? If I had Physics2D.ThickRayCast where the only difference from an ordinary raycast was that I could specifiy the width of the ray then it would solve all my problems.
     
    Last edited: Aug 6, 2020
  7. gyx920820

    gyx920820

    Joined:
    Oct 8, 2015
    Posts:
    35
    I found that when set default contact offset as 0.015, it works perfectly
     
    spark-man likes this.
  8. spark-man

    spark-man

    Joined:
    May 22, 2013
    Posts:
    96
    Yeah works much better now. You are life saver thank you very much. :)