- Home /
Find cardinal direction of collision based on 2D Cartesian coordinates
Basically I want to find the angle/direction/whatever at the point where an object hits a wall in a 2D Cartesian space (x y). I'd like to be able to map this to one of the four cardinal directions: Up, Down, Left Right. My object does not rotate, it's just a sprite that plays a different animation depending on key presses.
The problem is that, while I have Vector2s for the object and the wall, the wall (i.e. its collider) is quite long, so just comparing the transform.position of each object won't really work, because the wall's "position" (I assume the centre of its area) could be somewhere far away from the impact point.
Then I found out about collision.contacts[0].point, which apparently gives the point of contact between two colliders. So I'm currently using that in the form of:
Vector2 dir = collision.contacts[0].point - (Vector2)transform.position;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg;
And then trying to hard-code the angle to correspond to one of the four directions, e.g. angle > 145 = Left.
But this doesn't work how I expect all the time. For example, sometimes although the object hits a wall to its left, giving an angle of 130, this makes it think it's hit a wall above it. Playing with the ranges doesn't really help because I keep finding cases where it doesn't quite work. I did also try Vector2.Angle, but this produces basically the same problem, and also doesn't give me the results I expect in the first place (probably because I've misunderstood how it works).
So I think I must be missing something regarding my initial approach. Is there a better way to do this?
Answer by LCStark · Sep 22, 2018 at 05:13 PM
Regarding the Vector2.Angle
- I think you want to use Vector2.SignedAngle
instead. Angle
would give you +90 degree angle for both left and right.
So upon doing:
Vector2 dir = collision.contacts[0].point - (Vector2)transform.position;
float signed = Vector2.SignedAngle(dir, (Vector2)transform.position);
I can map the cardinal direction as such: Left = (-180 to -90), Up = (-90 to 0), Right = (0 to 90), Down = (90 to 180). SignedAngle seemed to do the trick, no issues so far. Thanks a lot!
Ah, there's your problem. You're getting the SignedAngle
between dir
and position
, which is the wrong thing to do. You want to compare the direction with some reference vector (e. g. Vector2.up).
float signed = Vector2.SignedAngle(dir, Vector2.up)
I don't think I can use Vector2.up (or forward, or whatever) because my object doesn't rotate, so it'll always have the same "up". Anyway, SignedAngle seems to be working ok, I don't know if it's perfect but it works a lot better than what I had before.
EDIT: Ok, so there is a problem - I got hit to the left, and wanted the angle to be in the (-180, -90) range, but I got +145. It happened when I clipped the very bottom right corner of a collider. SO maybe you are right and I need to have some sort of notion of "forward" - I might have to do this manually since my sprite doesn't rotate. I think I can use $$anonymous$$oveDirection, if I just keep track of this when a force is applied and compare against it.