Circle colliders and axis-aligned bounding rectangles are two common simple ways to detect if two objects are colliding in a 2D video game. Other collider types exist such as polygon colliders, but that will be for a future blog post. Many times programmers simplify the shape of the character when adding colliders to reduce the complexity of the calculations. Today you will learn two simple ways to calculate if two circles overlap or two rectangles overlap.

CircleDistance

Figure 1: Two circles with radius r1 and r2

Circle colliders

Circle colliders are one of the simplest types of collision detections. To find if two circles intersect, you start by calculating the distance between the two circles. If that distance is less than the combined radius of each circle, they are colliding. See figures 1 and 2.

You can see the distance between the circle centers is larger than the sum of the radii of the two circles. For a concrete example, imagine the first circle has a radius of 10 and the second circle has a radius of 20. Then imagine the distance between the circles is 50. 10 + 20 is 30, which is less than 50. Therefore, the circles are not overlapping.

Let’s look at overlapping circles now:

CircleDistanceOverlapped

Figure 2: Two overlapping circles with radius r1 and r2

The sum of the radius of each circle is now greater than the distance between them. You can see the length of r1 + the length of r2 combined is greater than the distance between the circle centers.

Circle colliders: code example

Here is a code example in C++:

#include <cmath>

struct Circle
{
    double radius;
    double x;
    double y;

    double GetDistanceFrom(const Circle &other) const {
        const double horizontalDelta = other.x - this->x;
        const double verticalDelta = other.y - this->y;
        const double squaredDeltaSum = pow(horizontalDelta, 2) + pow(verticalDelta, 2);
        const double distance = sqrt(squaredDeltaSum);
        return distance;
    }

    bool IsOverlapping(const Circle &other) const
    {
        const double combinedRadii = this->radius + other.radius;
        const double distanceApart = this->GetDistanceFrom(other);
        if (distanceApart >= combinedRadii )
            return false;
        return true;
    }
};

GetDistanceFrom calculates the distance between two 2D points. The distance is equal to sqrt(horizontalDelta^2 + verticalDelta^2), where horizontalDelta is the difference in X between the points, and verticalDelta is the difference in Y between the points. This corresponds to the Pythagorean Theorem, which states a^2 + b^2 = c^2. If you imagine the two points forming a right triangle, the distance will correspond to the hypotenuse of the triangle, which is equal to the square root of c.

IsOverlapping calculates whether the two circles overlap. If the circles are further apart than their combined radii, then they do not overlap. Figure 1 illustrates when that would happen. Figure 2 shows two circles that are overlapping. You can see visually when we add the distance of the radii together, it is longer than the distance between the two circles. Therefore, the circles overlap.

Circle colliders: example code

Here is an example program that you can run, modify the variables, and see for yourself that it works properly:

#include <iostream>
using namespace std;
int main()
{
    Circle circle1 = {
        .radius = 1,
        .x = 0,
        .y = 0,
    };
    Circle circle2 = {
        .radius = 1.5,
        .x = 2,
        .y = 0,
    };

    cout << "circle1 overlaps circle2: " << (circle1.IsOverlapping(circle2) ? "true" : "false") << endl;
    // prints "circle1 overlaps circle2: true"

    Circle circle3 = {
      .radius = 2,
      .x = 5,
      .y = 5
    };

    cout << "circle1 overlaps circle3: " << (circle1.IsOverlapping(circle3) ? "true" : "false") << endl;
    // prints "circle1 overlaps circle3: false"

    return 0;
}

Axis-Aligned Bounding Rectangle Colliders

Another simple example of collision detection is with axis-aligned bounding rectangles, which are rectangles without rotation. The name sounds more complicated than it is. Axis-aligned just means that the rectangle is not rotated and therefore lines up with the x and y axis. It simplifies the math to not have to worry about the rectangles rotating when calculating collisions. The way you can tell if two axis-aligned bounding rectangles overlap is by checking the relationship between the two sides of each rectangle. If any side is past the opposite side, then they don’t overlap. The images below will add clarity.

Take a look at this image of two overlapping rectangles:

RectangleOverlapped

Figure 3: Two overlapping rectangles

We define a rectangle as a position with a width and a height. The X position increases to the right, and the Y position increases as we go down. If you work in a different coordinate system you will need to modify the equations that will soon follow. But the principles should be the same for detecting overlap between two axis-aligned rectangles. The rectangles in each figure are axis-aligned, meaning they are not rotated relative to the x and y axis.

Figure 4 shows an example of two rectangles that do not overlap, along with sample coordinates:

RectangleNoOverlap

Figure 4: Two rectangles that are not overlapped

Calculating whether two rectangles overlap

Rectangle1 and Rectangle2 are not overlapping if any of the following are true:

  • The left side of rectangle1 is to the right of rectangle2: RectangleNoOverlap

Figure 5: Not overlapping: left is past right

  • The right side of rectangle1 is to the left of rectangle2:

RectangleNoOverlap

Figure 6: Not overlapping: right is before left

  • The top of rectangle1 is below the bottom of rectangle2:

RectangleNoOverlap

Figure 7: Not overlapping: top is below bottom

  • The bottom of rectangle1 is above the top of rectangle2

RectangleNoOverlap

Figure 8: Not overlapping: bottom is above top

If any of those conditions are true, then the rectangle is not overlapping. Otherwise, it is overlapping.

AxisAlignedBoundingRectangle code example

Let’s see how this looks with some code. Here is an example of an AxisAlignedBoundingRectangle:

struct AxisAlignedBoundingRectangle
{
    double x;
    double y;
    double width;
    double height;

    // Assumes an axis where x increases to the right and y increases down
    // Also assumes touching rectangles are not overlapping
    // (0,0)
    //   -----> +x
    //   |
    //   |
    //   v +y
    bool IsOverlapping(const AxisAlignedBoundingRectangle &other) const
    {
        // The rectangle can't be overlapping if any of the following are true:
        if (
            // 1. The left side of this rectangle is to the right of the other rectangle
            this->x >= other.x + other.width ||
            // 2. The right side of this rectangle is to the left of the other rectangle
            this->x + this->width <= other.x ||
            // 3. The top of this rectangle is past the bottom of the other rectangle
            this->y >= other.y + other.height ||
            // 4. The bottom of this rectangle is above the top of the other rectangle
            this->y + this->height <= other.y)
        {
            return false;
        }
        return true;
    }
};

I added comments for clarity and what assumptions I was making when I wrote the code. The images above explain the same thing that the comments in the code are trying to convey. So the two rectangles are not overlapping if:

  1. The left side of this rectangle is past the right side of the other rectangle OR
  2. The right side of this rectangle is before the left side of the other rectangle OR
  3. The top side of this rectangle is below the bottom side of the other rectangle OR
  4. The bottom side of this rectangle is above the top side of the other rectangle

Otherwise, the rectangles overlap. Once you intuitively understand what those mean, calculating the overlap makes much more sense.

Overlapping rectangles: code example

Here is a main function that shows what an overlapping example could look like:

#include <iostream>
using namespace std;
int main()
{
    // Overlapping rectangles
    AxisAlignedBoundingRectangle rectangle1 = {
        .x = 5,
        .y = 10,
        .width = 10,
        .height = 21,
    };
    AxisAlignedBoundingRectangle rectangle2 = {
        .x = 8,
        .y = 27,
        .width = 9,
        .height = 12,
    };

    cout << "rectangle1 overlaps rectangle2: " << (rectangle1.IsOverlapping(rectangle2) ? "true": "false") << endl;
    // prints "rectangle1 overlaps rectangle2: true"
}

The above code corresponds to Figure 3. Here it is again for reference:

RectangleOverlapped

Figure 3 (again): Two overlapping rectangles

Figure 3 shows two rectangles: rectangle1 and rectangle2. The two rectangles overlap since none of the conditions hold true for rectangle1 relative to rectangle2: the left is not past the right, the right is not before the left, the top is not below the bottom, and the bottom is not above the top of the other rectangle.

Non-overlapping rectangles: code example

Here is a code example of the rectangles not overlapping:

#include <iostream>
using namespace std;
int main()
{
    // Non-overlapping rectangles
    rectangle1 = {
        .x = 5,
        .y = 10,
        .width = 10,
        .height = 21,
    };
    rectangle2 = {
        .x = 18,
        .y = 27,
        .width = 5,
        .height = 12,
    };
    cout << "rectangle1 overlaps rectangle2: " << (rectangle1.IsOverlapping(rectangle2) ? "true": "false") << endl;
    // prints "rectangle1 overlaps rectangle2: false"
}

That code corresponds to this image:

RectangleNoOverlap

Figure 9: Two overlapping rectangles

Since the right side of Rectangle1 is to the left of rectangle2, it is not overlapping.

Conclusion

I hope this helps you have a more intuitive understanding of the math behind a couple of simple 2D collision math used in 2D video games. There are many more ways to calculate collisions but this is one way to get you started. There is a lot more to learn about collision detection. Good luck with making your games. I hope you have a great rest of your day. Thank you for reading.