detect side of collision in box collider 2d?
I'm new to unity3d. I have seen this question has been asked in many places but I couldn't figure out how to solve this problem. I have two objects with box collider 2d target and a ball with Circle Collider 2d. I want to detect the side of target box when ball hits the target. simply my question is how to detect the side ball hits in the box(top,left,bottom or right). I could get the the position of the hitting object with following code but it's useless.
void OnCollisionEnter2D(Collision2D collision)
{
Collider2D collider = collision.collider;
if(collider.name== "target")
{
print(collider.name);
ContactPoint2D contact = collision.contacts[0];
Vector3 pos = contact.point;
print(pos);
}
}
Take a look at this https://www.malgol.com/how-to-detect-collision-side-in-unity-2d/ should work with any collider. Just download and import the code.
Answer by kacyesp · Sep 02, 2014 at 11:26 AM
Use collider.bounds.center and compare it with the point.
void OnCollisionEnter2D(Collision2D collision)
{
Collider2D collider = collision.collider;
if(collider.name == "target")
{
Vector3 contactPoint = collision.contacts[0].point;
Vector3 center = collider.bounds.center;
bool right = contactPoint.x > center.x;
bool top = contactPoint.y > center.y;
}
}
Thank you for the effort @kacyesp. I used ray Physics2D.Linecast to draw a line and detect the side. thank you again for the answer.
How would I do this for an OnTriggerEnter2D function?
I tried this script.But whenever the object collides from the top and bottom,The right collider gets hits.and when the object collides from left and right the script is working.When I removed the horizontal collision, Vertical collisions are working just fine.Anyone know why both of them are not working together
Answer by Kodekool · Oct 01, 2015 at 12:02 PM
This is going to be a little basic of me, but please forgive my ignorance, can anyone explain a bit as to why this works? or point me to a resource where I can read more about it. i'm a little confused.
Refer to the image. The rectangle is your collider and the circle is the inco$$anonymous$$g object. If ( contactPoint.x > center.x ), this means that the center of circle is on the right of center of rectangle. If (contactPoint.y > center.y ), the center of circle is on the top of center of rectangle. You may want to check the coordinates with stronger conditions, like:
void OnCollisionEnter2D(Collision2D collision)
{
Collider2D collider = collision.collider;
bool collideFromLeft;
bool collideFromTop;
bool collideFromRight;
bool collideFromBottom;
int RectWidth = this.GetComponent<Collider2D> ().bounds.size.x;
int RectHeight = this.GetComponent<Collider2D> ().bounds.size.y;
int circleRad = collider.bounds.size.x;
if(collider.name == "target")
{
Vector3 contactPoint = collision.contacts[0].point;
Vector3 center = collider.bounds.center;
if (contactPoint.y > center.y && //checks that circle is on top of rectangle
(contactPoint.x < center.x + RectWidth / 2 && contactPoint.x > center.x - RectWidth / 2)) {
collideFromTop = true;
}
else if (contactPoint.y < center.y &&
(contactPoint.x < center.x + RectWidth / 2 && contactPoint.x > center.x - RectWidth / 2)) {
collideFromBottom = true;
}
else if (contactPoint.x > center.x &&
(contactPoint.y < center.y + RectHeight / 2 && contactPoint.y > center.y - RectHeight / 2)) {
collideFromRight = true;
}
else if (contactPoint.x < center.x &&
(contactPoint.y < center.y + RectHeight / 2 && contactPoint.y > center.y - RectHeight / 2)) {
collideFromLeft = true;
}
}
}
Thanks. I'd actually done a lot of reading on this since posting the question so I did understand, but I really appreciate you taking the time to give me this explanation.
From researching and program$$anonymous$$g this, this will not work. The code as it stands cannot deter$$anonymous$$e if the contact is truly on the bottom when it could actually be on the lower left or lower right and still be true for all checks for the bottom condition.
One Idea that I have is to find the angle from the center to the point of contact. If that angle appears in a specific part of the box, we have our side.
For example from the center to the topleft and topright there is an angle between the two lines which connect to these corners from the center. If my contact point is between these two angles then I know exactly what side I am on. I can assume a side if the angle is equal.
Answer by brdavid_unity · Jan 19, 2020 at 09:47 PM
For the curious, I solved this problem using the following code
private string WhatSideOfTheColliderWasHit(Collider2D collision)
{
Vector2 PointOnBoxHit = collision.ClosestPoint(transform.position);
Vector2 centerOfObject = collision.bounds.center;
float xMinPoint = Mathf.Abs((collision.bounds.size.x/2) - centerOfObject.x);
float xMaxPoint = Mathf.Abs(xMinPoint + collision.bounds.size.x);
float yMinPoint = Mathf.Abs((collision.bounds.size.y / 2) - centerOfObject.y);
float yMaxPoint = Mathf.Abs(yMinPoint + collision.bounds.size.y);
if (PointOnBoxHit.x >= xMinPoint && PointOnBoxHit.x <= xMaxPoint && Approximately(yMaxPoint, PointOnBoxHit.y, .1f))
return "Bottom";
else if (PointOnBoxHit.x >= xMinPoint && PointOnBoxHit.x <= xMaxPoint && Approximately(yMinPoint, PointOnBoxHit.y, .1f))
return "Top";
else if (PointOnBoxHit.y >= yMinPoint && PointOnBoxHit.y <= yMaxPoint && Approximately(xMaxPoint, PointOnBoxHit.y, .1f))
return "Right";
else
return "Left";
}
The basic idea is that I grab the closest point on the collider box where the collision happened. I then get the calculate the min/max of x and y of this particular box. I then simply compare my point to these min/max values. It tells exactly what side of the box I am on.
Also Approximately is my own function that basically checks to see if the two values are within a threshold. It's like Mathf.Approximately but I can control the epsilon.
Edit: You may have a problem with certain blocks returning size = 0,0,0 in some cases. If this happens then just go after size from the component
Vector3 size = collision.gameObject.GetComponent<BoxCollider2D>().size;
That fixed the issue for me. Then for the code above that calls for size, just replace collision.bounds.size with just size.
Answer by Tioboon · Sep 26, 2021 at 03:36 PM
Here is a easier way to make that:
Get the collision point by ClosestPoint (https://docs.unity3d.com/2019.1/Documentation/ScriptReference/Collider2D.ClosestPoint.html)
Get the distance from collision object center (using bounds.center) to closestPoint
Get the angle of the distance
Draw a box somewhere and trace lines to determine wich part of the box will make a different action.
Create a enum for each one of them.
Check the angles and return the enum.
Here is the code:
private static CollisionSide CheckIfFloorIsUnder(Collider2D thisCollider, Collider2D otherCollider)
{
var closestPoint = otherCollider.ClosestPoint(thisCollider.bounds.center);
var distance = closestPoint - (Vector2)otherCollider.bounds.center;
var angle = Vector2.Angle(Vector2.right, distance);
if (angle < 135 && angle > 45)
{
return CollisionSide.Under;
}
//The rest of sides by angle
return CollisionSide.None;
}
public enum CollisionSide
{
Under,
Above,
Sides,
None,
}
Your answer
Follow this Question
Related Questions
Bounds.Intersects returns false while collision still works? 1 Answer
How to kill enemy when the bullet hits the BoxColllider2D? 1 Answer
How to keep gameObjects set as triggers to only trigger once, even after a scene reload? 0 Answers
2D Collider Problem 1 Answer
creating an alternative to box collider 2d question 0 Answers