- Home /
 
Correcting for a collision overlapping too much?
I have a TileMap with a TileMapCollider2D and a Sprite with a BoxCollider2D. I'm not using physics at all so I'm correcting for the collision on my own. Here's my attempt:
 void FixedUpdate() {
     float h = Input.GetAxis("Horizontal") * Time.deltaTime * this.Speed;
     float v = Input.GetAxis("Vertical") * Time.deltaTime * this.Speed;
     Vector3 pos = this.transform.position;
     pos.x += h;
     pos.y += v;
     foreach (Tilemap map in this.Maps) {
         TilemapCollider2D mapc = map.GetComponent<TilemapCollider2D>();
         ColliderDistance2D dist = this.boxCollider.Distance(mapc);
         if (dist.isOverlapped && dist.isValid) {
             Debug.DrawLine(dist.pointB, dist.pointA, Color.white);
             Vector2 correction = dist.normal * dist.distance;
             pos += (Vector3)(correction);
         }
     }
     this.transform.position = pos;
 }
 
               This logic is on the blue square in this gif:

According to the documentation, dist.normal * dist.distance should be exactly the distance and direction required to make the two colliders touch. However you can see that I can push a few pixels into the red walls. When I release the button it takes several frames to back out of the wall. It goes a little haywire too when I go diagonally into the corner.
Answer by Nikaas · Dec 29, 2017 at 08:30 AM
TLDR: Insert this.transform.position = pos; at line 17 (just before the foreach loop). 
When i had such problems it always was code reordering issue. To me it looks like it is because you are adding to the pos vector and applying it as current position at the end. But you are calculating the collision according to boxCollider's last/previouse frame (i.e. h and v are not taken into account) . In other words your collision check is one frame late - you check if there was collision last frame and apply the movement after that.
You should apply pos as transform.position before calculating ColliderDistance2D (or find a way to check against pos itself).
Or you can try to apply pos only if there is no collision/overlapping.
Thank you for the answer. I just had the same problem and turned out it was because of this.
Answer by theterrificjd · Dec 28, 2017 at 01:34 PM
Long shot answer attempt:
Usually Distances formulas are usually from centers of the transforms, meaning approaching at non-perpendicular angles produce different distances.
I think you may want something to do with Bounds properties of the colliders instead.
I've only used physics so far, and haven't done this personally, but I think a few of the Bounds functions look useful. My thinking is the Intersects / ClosestPoint in combination (if the objects bounds intersects the wall's boundes, adjust the objects closest point to
The short white line you see in the gif is me illustrating pointA and pointB given by the distance formula. They don't appear to be co$$anonymous$$g from the middle of the colliders. However switching to using the bounds may be a better solution, I'll try it and report back. 
Bounds are way too generic. It refers to a rectangle encompassing EVERY Tile collider not EACH Tile collider.
Answer by JusSumGuy · Dec 28, 2017 at 12:57 PM
I had this problem too with a game I was designing. I'm looking forward to seeing the answer to this one , because I fixed it with a not so elegant approach. But I'm pretty sure it has something to do with how the physics components are interacting with each other. When you add force to the collider it keeps pushing towards the other collider that's why you have that little overlap with a reversed force. In the corner you get the haywire because now the opposite force is pushing back from two directions. Hope this helps lol, but thanks for asking the solution will help me out as well :).
I'm foregoing the physics of Unity. It's a top down game that wouldn't benefit from a physics engine so I'm not applying forces or adding rigid bodies. I'm only using colliders because of how the Tile$$anonymous$$ap can automatically construct colliders around the sprites of tiles. I'm manipulating transform.position directly. 
Answer by BOB_KSE · Dec 28, 2017 at 06:59 PM
It's happening because the player is trying to force its way into the collider on that frame and on the next frame collision is detected and the player is pushed back. I have a not so elegant solution.
when the player hits the "red walls" using "uparrow" for example. just take away user's ability to press "uparrow" anymore, using boolean variables and OnCollisionStay2D() function and OnCollisionExit2D() give back control. I have never tried it though. I am suffering from the same problem, but left it as it is.
https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnCollisionStay2D.html https://docs.unity3d.com/ScriptReference/MonoBehaviour.OnCollisionExit2D.html
So far I'm not using any of the OnCollisionX events because I want to respond to the collision the same frame it happens (before drawing so you never actually see the overlap happen) and nudge the player back just enough so the player is resting against the wall. The movement of the player and the nudging back of the player are currently happening at the same frame so it shouldn't be possible for the player to ever be drawn overlapping the wall collider but apparently my nudge back isn't working how I'd like.
Answer by coreyog · Dec 29, 2017 at 05:23 AM
For now, I've added a RigidBody2D and tweaked some of the Project Settings for Physics2D until I have what I want. It still presses into the walls but not nearly as much as before. You can't notice it. Also, because of the slight pressing into walls, I've given the BoxCollider2D a smaller size and a radius. The rounded corners prevent it from catching on walls that are flush with each other.

I didn't realize that a rigid body would reject collisions even if I'm not applying forces. This may not be the optimal solution since it's using the physics engine to achieve the push back but it's getting me the results I'm after. I'll over-optimize later if this has a noticeable impact on performance.
BTW, I'm not accepting this as the answer because I'm hopeful for a non-physics approach like I was trying before. $$anonymous$$aybe if this goes long enough without a solution I'll accept this.
Cool, that's a pretty good solution! I'll keep this in $$anonymous$$d. And hey if you ever come across a situation where you need your object to keep vibrating side to side you already know how to do that as well. Usually I find the cool tricks by mistake lol.
don't stop your project because of the inconvenience. you will surely find a solution later somewhere. happy developing :)
Your answer
 
             Follow this Question
Related Questions
Unity2D - OnTriggerEnter2D not working 1 Answer
Using child colliders with rigidbodies/joints in 2D 0 Answers
Problem with method Collider2D.isTouchingLayers() 4 Answers
Find next corner of a 2d pollygon collider 0 Answers
Why is there a gap between my player and the wall during wall slide? SOLVED 2 Answers