Skip to Content
Course content

155: Basic Collision Detection Concepts

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Collision detection sounds like a heavy physics problem, but for most 2D games, we start with something much simpler: Axis-Aligned Bounding Boxes, or AABB. "Axis-aligned" just means the rectangles aren't rotated. They stay perfectly upright, which makes the math incredibly cheap. If you're building a top-down shooter or a platformer, this is where you start.

Defining our Bounding Boxes

To get this working, we need a way to represent a rectangle in space. I'm going to use a simple struct. I prefer structs for these kinds of data-only containers because it keeps the syntax clean. We only need the top-left coordinates and the dimensions.

struct Rect {
    float x, y;
    float width, height;
};

In a real project, you'd probably have a GameObject class that has a Rect for its hit-box, but for this example, we'll just work with the rectangles directly to keep the focus on the logic.

Writing the Overlap Logic

The goal is to determine if two rectangles are overlapping. The easiest way to think about this isn't "are they touching?" but rather "is it impossible for them to be touching?" If the left side of Rect A is to the right of the right side of Rect B, they cannot possibly overlap. We check for all four sides.

Here is my first pass at the function:

bool checkCollision(Rect a, Rect b) {
    // Check if A is to the right of B, or B is to the right of A
    if (a.x > b.x + b.width || b.x > a.x + a.width) {
        return false;
    }
    // Check if A is below B, or B is below A
    if (a.y > b.y + b.height || b.y > a.y + a.height) {
        return false;
    }
    return true;
}

Fixing the "Ghost Collision" Bug

I actually ran into a bug with the logic above during a project a few years back. I noticed that if two objects were exactly side-by-side—meaning a.x + a.width was exactly equal to b.x—the function returned true. In a game, this feels "sticky." The player would trigger a collision event even if they were just brushing against a wall without actually penetrating it.

The fix is subtle: we need to decide if "touching" counts as "colliding." For most gameplay, we only care if they actually overlap. I'll change the greater-than signs to include equality. This way, if the edges are exactly flush, it returns false.

bool checkCollision(Rect a, Rect b) {
    // Using >= instead of > prevents "ghost" collisions when edges are flush
    if (a.x >= b.x + b.width || b.x >= a.x + a.width) {
        return false;
    }
    if (a.y >= b.y + b.height || b.y >= a.y + a.height) {
        return false;
    }
    return true;
}

Putting it into a Game Loop

Now, let's see how this looks when we actually simulate a player moving toward an enemy. I'll set up a small loop where we move the player's X position and check for a collision every frame.

#include <iostream>

int main() {
    Rect player = { 0.0f, 0.0f, 32.0f, 32.0f };
    Rect enemy = { 100.0f, 0.0f, 32.0f, 32.0f };

    std::cout < "Moving player toward enemy...< std::endl;

    while (player.x < 150.0f) {
        player.x += 10.0f; // Move right
        
        if (checkCollision(player, enemy)) {
            std::cout < "Collision detected at x = " < player.x < "!" < std::endl;
            break; 
        } else {
            std::cout < "No collision at x = " < player.x < std::endl;
        }
    }

    return 0;
}

You'll notice that the collision triggers once the player's right edge (x + 32) exceeds the enemy's left edge (100). Since we move by 10 units per "frame," the overlap happens quickly. This logic is the foundation for almost everything else in 2D spatial detection.




📋 Practical Task

Implement an AABB-based Trigger Zone

In many games, you have "Trigger Zones" (like a doorway that opens a menu or a trap that springs) that are separate from the player's physical walls. Your task is to create a program that simulates a player walking through a specific trigger zone.

Requirements:

  • Create a Rect struct.
  • Implement the checkCollision function using the logic we discussed (preventing ghost collisions).
  • Define a player rectangle and a triggerZone rectangle.
  • Write a loop that moves the player across the screen (incrementing x).
  • The program should print "Safe" while the player is outside the zone, and "Trigger Activated!" the moment the player's bounding box overlaps with the trigger zone.
  • Once the player has completely exited the trigger zone on the other side, the program should print "Zone Cleared" and then terminate.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.