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);
		}
	}

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;
        }
    }

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.

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.

Here is a easier way to make that:

  • Get the collision point by ClosestPoint
    (Unity - Scripting API: Collider2D.ClosestPoint)
  • 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,
}