Collision Detection — the Basic Physics of Every Video Game

By Carlos Montiel | Enterprise AI Specialist
Leer en español →
Published: 2026-07-28 | By: Carlos Montiel | Reading time: ~4 minutes

Almost everything that makes a video game interesting depends on knowing when two things touch. Today we formalize that question with simple math and reusable code.

Why This Matters More Than It Seems

In the previous lesson we handled sprite animation. Before that, in Pong, we used `SDL_HasIntersection` to detect when the ball touched a paddle — a quick but limited solution. In this lesson we'll understand what that function does internally, and we'll build collision detection that works for both rectangles and circles, because not every game uses only boxes.

Collision detection is the foundation of: combat damage, item pickups, hits from projectiles, characters that can't walk through walls, and practically any physical interaction in a 2D game.

Rectangle Collision: AABB

AABB stands for "Axis-Aligned Bounding Box" — a box aligned to the axes, meaning no rotation. It's the cheapest collision shape to compute and the most common one in 2D games.

The logic is simple: two rectangles do NOT overlap if one is entirely to the left, right, above, or below the other. If none of those four conditions is true, they're touching.

struct AABB { float x, y; // top-left corner float width, height; }; bool aabb_collide(const AABB& a, const AABB& b) { bool separated_on_x = (a.x + a.width <= b.x) || (b.x + b.width <= a.x); bool separated_on_y = (a.y + a.height <= b.y) || (b.y + b.height <= a.y); return !(separated_on_x || separated_on_y); }

This is exactly what `SDL_HasIntersection` does internally. Now that you understand it, you can extend it — for example, computing how much overlap there is (to resolve the collision by pushing the objects apart) instead of just knowing whether they collide.

struct Overlap { bool has_collision; float depth_x; float depth_y; }; Overlap compute_overlap(const AABB& a, const AABB& b) { if (!aabb_collide(a, b)) return { false, 0, 0 }; float overlap_right = (a.x + a.width) - b.x; float overlap_left = (b.x + b.width) - a.x; float overlap_bottom = (a.y + a.height) - b.y; float overlap_top = (b.y + b.height) - a.y; float smallest_x = std::min(overlap_right, overlap_left); float smallest_y = std::min(overlap_bottom, overlap_top); return { true, smallest_x, smallest_y }; }

Circle Collision

For round objects (a ball, an explosion, a projectile), circle collision is more precise and, surprisingly, simpler to compute: two circles collide if the distance between their centers is less than the sum of their radii.

struct Circle { float x, y; // center float radius; }; bool circles_collide(const Circle& a, const Circle& b) { float dx = a.x - b.x; float dy = a.y - b.y; float distance_squared = dx * dx + dy * dy; float radius_sum = a.radius + b.radius; return distance_squared <= (radius_sum * radius_sum); }

Notice the performance trick: we compare the squared distance against the squared sum of the radii instead of using `sqrt()`. Square root is a relatively expensive operation, and here it's completely avoidable — we only care whether one distance is greater or smaller than another, not its exact value.

Circle vs. Rectangle Collision

A very common mixed case: a round ball against a rectangular platform. The standard technique is to find the point on the rectangle closest to the circle's center, and measure the distance from there.

bool circle_rect_collide(const Circle& c, const AABB& r) { float closest_x = std::max(r.x, std::min(c.x, r.x + r.width)); float closest_y = std::max(r.y, std::min(c.y, r.y + r.height)); float dx = c.x - closest_x; float dy = c.y - closest_y; return (dx * dx + dy * dy) <= (c.radius * c.radius); }

Applying It to Pong: Real Ball Collision

Now we can replace the improvised `SDL_HasIntersection` from lesson 3 with our own AABB function, and use the overlap to decide whether the bounce should be horizontal or vertical based on which side the impact happened on.

AABB rect_of(const SDL_Rect& r) { return { (float)r.x, (float)r.y, (float)r.w, (float)r.h }; } void resolve_ball_paddle_collision(Ball& ball, const Paddle& paddle) { AABB ball_box = rect_of(ball.rect); AABB paddle_box = rect_of(paddle.rect); Overlap o = compute_overlap(ball_box, paddle_box); if (!o.has_collision) return; if (o.depth_x < o.depth_y) { ball.vel_x = -ball.vel_x; } else { ball.vel_y = -ball.vel_y; } }

Avoiding Double Collisions and "Jitter"

A frequent bug: if you don't separate the objects after detecting the collision, the same hit gets detected across several consecutive frames and the object "shakes" or gets stuck. The fix is to push the objects out of the overlap zone immediately after resolving the physics.

void separate_objects(SDL_Rect& to_move, const Overlap& o, bool x_axis) { if (x_axis) { to_move.x += (o.depth_x > 0) ? (int)o.depth_x : -(int)o.depth_x; } else { to_move.y += (o.depth_y > 0) ? (int)o.depth_y : -(int)o.depth_y; } }

A Good Use of Your AI Assistant Here

Collision geometry is an area where AI assistants are particularly good at explaining "why" a formula works, not just "what" it does. If the math behind the closest-point circle-rectangle collision isn't fully clear to you, ask your assistant to draw it out in ASCII or explain it with a concrete numeric case (for example, a circle at `(50, 50)` with radius `10` against a rectangle at `(0,0,40,40)`). Watching the numbers move helps far more than the formula alone.

With collisions solved, in the next lesson we'll use these same data structures (positions, character states) as the foundation for something different: a save system that gives your game persistent memory between sessions.

Carlos Montiel
Enterprise AI Solutions Architect
Specialist in LLMs, Agents, and Orchestration
guatemalia.com/en/#contact · info@guatemalia.com

Need to implement AI at your company?

Carlos Montiel is an enterprise AI solutions architect. He implements LLMs, Agents, RAG, and orchestrators for companies across Guatemala and Latin America. Reach out for a consultation.

Contact Carlos Montiel

info@guatemalia.com