C++
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Object-Oriented C++
-
Section 4: Memory Management
-
Section 5: Templates and Generic Programming
-
Section 6: The Standard Template Library
-
Section 7: Modern C++ Features
-
Section 8: Error Handling
-
Section 9: Multithreading
-
Section 10: Operator Overloading and Type Conversion
-
Section 11: Advanced Topics
-
Section 12: Tooling and Build Systems
-
Section 13: Design Patterns in C++
-
Section 14: Interfacing with C and Systems Programming
-
Section 15: Networking and IPC Basics
-
Section 16: Graphics and Game Programming Basics
-
Section 17: The Boost Libraries
-
Section 18: Data Structures and Algorithms in C++
-
Section 19: Practical Projects
-
Section 20: More Concurrency Patterns
-
Section 21: More OOP and Design Practice
-
Section 22: File I/O and Streams
-
Section 23: More Standard Library
-
Section 24: Practice Exercises
-
Section 25: Interview and Algorithm Practice
-
Section 26: Compiler and Language Internals
-
Section 27: GUI and Application Frameworks Overview
-
Section 28: Testing and Quality Practices
-
Section 29: Numerics Library
-
Section 30: Concepts Library (C++20)
-
Section 31: Ranges Library (C++20) In Depth
-
Section 32: More Utility Library
155: Basic Collision Detection Concepts
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
Rectstruct. - Implement the
checkCollisionfunction using the logic we discussed (preventing ghost collisions). - Define a
playerrectangle and atriggerZonerectangle. - 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.
There are no comments for now.