/**
                     * sort Used to order an array of integers in ascending order (O(n)).
                     * @param {Array} arr
                     * @return {Promise}
                    */
                    
                    function sort (arr) {
                        return new Promise(resolve => {
                            const sorted = [];
                            
                            for (const item of arr) {
                                setTimeout(item => sorted.push(item), item, item);
                            }
                            
                            setTimeout(() => resolve(sorted), arr.reduce((a, b) => a + b, 0) + 1);
                        });
                    }
                
                
                    «Nullam elementum blandit molestie.
                    Aenean condimentum lectus ut felis.
                    Phasellus fringilla nisl tincidunt dolor.»
                    
                    «Nam quis ante sed neque rhoncus.
                    Proin porta, turpis quis iaculis.
                    Maecenas tristique vulputate magna, vel laoreet.»
                    
                    «Nullam lobortis turpis a tempor molestie.
                    Maecenas fringilla nisl at malesuada porta.»
                
            

How to Detect Collision Side in Unity 2D

Detecting the side of a collision might be fundamental for certain games, Unity doesn’t help doing this: when a collision occurs only basic information is calculated, like the contact points of the collision. This post explains how to get the collision side of a collision in Unity 2D and how to get the collision side generically starting from a contact point.

How to detect collision side

As a first step imagine two entities A and B in the game: for instance a Zombie and a Ninja, both with their own collider.

Suppose that one of the two collides with the other, for example the Zombie collides with the Ninja (A collides with B), at this phase the information necessary to retrieve the collision side is available: one collision contact point, the center point of the box containing the Zombie (A) and the maximal point of the box containing the Zombie (A).

Through those points the collision side can be retrieved: if the angle of the line passing through the contact point and the center of the Zombie is between the angle of the line passing through the maximal point and the center of the Zombie, and 360 degrees minus the same angle, then the collision side is Right, the same logic is applied for the other sides by varying the range of angles in which the angle between the center and the contact point must be between.

How to detect collision side in Unity 2D

To start, a collision side type is defined, it will be returned by the method that detects the collision side.

public enum Collision2DSideType {
    None,
    Left,
    Right,
    Top,
    Bottom,
}

The Collision2D class is extended by providing a method that returns the collision side type of the current collision instance. At this point the three points necessary to detect the collision side can be retrieved and passed to the method GetContactSide which is the implementation of the algorithm previously defined.

public static class Collision2DExtensions {
    public static Collision2DSideType GetContactSide (this Collision2D collision) {
        Vector2 contact = collision.GetContact(0).point;
        Vector2 center = collision.collider.bounds.center;
        Vector2 max = collision.collider.bounds.max;

        return GetContactSide(contact, center, max);
    }

    private static Collision2DSideType GetContactSide (Vector2 contact, Vector2 center, Vector2 max) {
        Collision2DSideType side = Collision2DSideType.None;
        float diagonalAngle = Mathf.Atan2(max.y - center.y, max.x - center.x) * 180 / Mathf.PI;
        float contactAngle = Mathf.Atan2(contact.y - center.y, contact.x - center.x) * 180 / Mathf.PI;

        if (contactAngle < 0) {
            contactAngle = 360 + contactAngle;
        }

        if (diagonalAngle < 0) {
            diagonalAngle = 360 + diagonalAngle;
        }

        if (
            ((contactAngle >= 360 - diagonalAngle) && (contactAngle <= 360)) ||
            ((contactAngle <= diagonalAngle) && (contactAngle >= 0))
        ) {
            side = Collision2DSideType.Right;
        }
        else if (
            ((contactAngle >= 180 - diagonalAngle) && (contactAngle <= 180)) ||
            ((contactAngle >= 180) && (contactAngle <= 180 + diagonalAngle))
        ) {
            side = Collision2DSideType.Left;
        }
        else if (
            ((contactAngle >= diagonalAngle) && (contactAngle <= 90)) ||
            ((contactAngle >= 90) && (contactAngle <= 180 - diagonalAngle))
        ) {
            side = Collision2DSideType.Top;
        }
        else if (
            ((contactAngle >= 180 + diagonalAngle) && (contactAngle <= 270)) ||
            ((contactAngle >= 270) && (contactAngle <= 360 - diagonalAngle))
        ) {
            side = Collision2DSideType.Bottom;
        }

        return side.Opposite();
    }
}

Note that if A collides with B, and the collision side of A is Left, the collision side of B will be the opposite of the collision side of A, which is Right in this specific example. This is why the Opposite method is defined for the Collision2DSideType enum, this allows to get the collision side of both A and B independently if the collision event is triggered in A or B.

public static class Collision2DSideTypeExtensions {
    public static Collision2DSideType Opposite (this Collision2DSideType sideType) {
        Collision2DSideType opposite;

        if (sideType == Collision2DSideType.Left) {
            opposite = Collision2DSideType.Right;
        }
        else if (sideType == Collision2DSideType.Right) {
           opposite = Collision2DSideType.Left;
        }
        else if (sideType == Collision2DSideType.Top) {
            opposite = Collision2DSideType.Bottom;
        }
        else if (sideType == Collision2DSideType.Bottom) {
            opposite = Collision2DSideType.Top;
        }
        else {
            opposite = Collision2DSideType.None;
        }

        return opposite;
    }
}

Usage Example

Given a Character class listening for a collision, the collision side can be retrieved from the Collision2D instance when a collision is verified.

public class Character : MonoBehaviour {
    private void OnCollisionEnter2D (Collision2D collision) {
        Collision2DSideType collisionSide = collision.GetContactSide();

        if (collisionSide == Collision2DSideType.Bottom) {
            // Handle Character bottom collision.
        }
        else if (collisionSide == Collision2DSideType.Right) {
            // Handle Character right collision.
        }
    }
}

Conclusion

By using the logic previously defined, retrieving the collision side of a collision becomes super easy using basic logic and trigonometry.