Collision Detection
Learn how to detect when game objects touch, overlap, or collide with each other.
Why Collision Detection?
Collision detection is essential for:
- Collecting coins or items
- Player hitting enemies
- Bullets hitting targets
- Player touching walls or boundaries
- Any game interaction between objects
Circle Collision (Distance-Based)
The most common method - check if two circles overlap:
let player = { x: 200, y: 200, size: 50 };
let coin = { x: 300, y: 250, size: 30 };
function draw() {
background(220);
// Draw player
fill(100, 150, 250);
circle(player.x, player.y, player.size);
// Draw coin
fill(255, 215, 0);
circle(coin.x, coin.y, coin.size);
// Check collision
let d = dist(player.x, player.y, coin.x, coin.y);
let minDist = (player.size + coin.size) / 2;
if (d < minDist) {
fill(0, 255, 0);
textAlign(CENTER);
text("COLLECTED!", 200, 50);
}
// Move player with mouse
player.x = mouseX;
player.y = mouseY;
}
Breaking it down
dist(x1, y1, x2, y2)- Calculates distance between two pointsminDist- Minimum distance before collision (sum of radii)- If actual distance is less than minimum, objects are colliding
- Works for any circular objects
Rectangle Collision (AABB)
Axis-Aligned Bounding Box collision for rectangles:
let player = { x: 150, y: 150, w: 50, h: 50 };
let box = { x: 250, y: 200, w: 60, h: 40 };
function draw() {
background(220);
// Draw player
fill(100, 150, 250);
rect(player.x, player.y, player.w, player.h);
// Draw box
fill(200, 100, 100);
rect(box.x, box.y, box.w, box.h);
// Check collision
if (player.x < box.x + box.w &&
player.x + player.w > box.x &&
player.y < box.y + box.h &&
player.y + player.h > box.y) {
fill(255, 0, 0);
textAlign(CENTER);
text("COLLISION!", 200, 50);
}
// Move player with arrow keys
if (keyIsDown(LEFT_ARROW)) player.x -= 3;
if (keyIsDown(RIGHT_ARROW)) player.x += 3;
if (keyIsDown(UP_ARROW)) player.y -= 3;
if (keyIsDown(DOWN_ARROW)) player.y += 3;
}
Breaking it down
- Check if rectangles overlap on both X and Y axes
- Four conditions must all be true for collision:
- Player's left edge is left of box's right edge
- Player's right edge is right of box's left edge
- Player's top edge is above box's bottom edge
- Player's bottom edge is below box's top edge
- Works for any axis-aligned rectangles
Point-Circle Collision
Check if a point (like mouse) is inside a circle:
let button = { x: 200, y: 200, size: 80 };
function draw() {
background(220);
// Check if mouse is inside circle
let d = dist(mouseX, mouseY, button.x, button.y);
let isInside = d < button.size / 2;
// Change color if hovering
if (isInside) {
fill(150, 200, 255);
} else {
fill(100, 150, 250);
}
circle(button.x, button.y, button.size);
}
function mousePressed() {
let d = dist(mouseX, mouseY, button.x, button.y);
if (d < button.size / 2) {
console.log("Button clicked!");
}
}
Breaking it down
- Point is at exact mouse coordinates
- Check distance from point to circle center
- If distance < radius, point is inside
- Used for: button clicks, hover detection, target hitting
Point-Rectangle Collision
Check if a point is inside a rectangle:
let button = { x: 150, y: 150, w: 100, h: 50 };
function draw() {
background(220);
// Check if mouse is inside rectangle
let isInside = mouseX > button.x &&
mouseX < button.x + button.w &&
mouseY > button.y &&
mouseY < button.y + button.h;
// Change color if hovering
if (isInside) {
fill(150, 200, 255);
} else {
fill(100, 150, 250);
}
rect(button.x, button.y, button.w, button.h);
}
Breaking it down
- Check if point is within bounds on both axes
- X must be between left and right edges
- Y must be between top and bottom edges
- Simpler than rectangle-rectangle collision
Circle-Rectangle Collision
More complex - circle colliding with rectangle:
function circleRectCollision(cx, cy, radius, rx, ry, rw, rh) {
// Find closest point on rectangle to circle
let closestX = constrain(cx, rx, rx + rw);
let closestY = constrain(cy, ry, ry + rh);
// Calculate distance from circle to closest point
let distance = dist(cx, cy, closestX, closestY);
// Collision if distance is less than radius
return distance < radius;
}
// Usage
let player = { x: 200, y: 200, size: 40 };
let wall = { x: 250, y: 150, w: 80, h: 100 };
function draw() {
background(220);
circle(player.x, player.y, player.size);
rect(wall.x, wall.y, wall.w, wall.h);
if (circleRectCollision(player.x, player.y, player.size/2,
wall.x, wall.y, wall.w, wall.h)) {
fill(255, 0, 0);
text("HIT!", 200, 50);
}
}
Breaking it down
- Find the closest point on rectangle to circle center
constrain(value, min, max)- Keeps value within range- Check distance from circle to that closest point
- More accurate than checking circle center against rectangle
Boundary Collision (Screen Edges)
Keep objects inside the canvas:
let player = { x: 200, y: 200, size: 50, speedX: 3, speedY: 2 };
function draw() {
background(220);
// Move player
player.x += player.speedX;
player.y += player.speedY;
// Bounce off edges (circle)
let radius = player.size / 2;
if (player.x - radius < 0 || player.x + radius > width) {
player.speedX *= -1; // Reverse horizontal direction
}
if (player.y - radius < 0 || player.y + radius > height) {
player.speedY *= -1; // Reverse vertical direction
}
circle(player.x, player.y, player.size);
}
Breaking it down
- Check if object touches any canvas edge
- For circles: check center ± radius
- Reverse speed to create bounce effect
- Can also use to stop movement or teleport
Common Patterns
Collecting Multiple Items
let player = { x: 200, y: 200, size: 40 };
let coins = [];
let score = 0;
function setup() {
createCanvas(400, 400);
// Create random coins
for (let i = 0; i < 10; i++) {
coins.push({
x: random(50, 350),
y: random(50, 350),
size: 30
});
}
}
function draw() {
background(220);
// Draw coins
fill(255, 215, 0);
for (let coin of coins) {
circle(coin.x, coin.y, coin.size);
}
// Draw player
fill(100, 150, 250);
circle(player.x, player.y, player.size);
// Check collisions (backwards to safely remove)
for (let i = coins.length - 1; i >= 0; i--) {
let coin = coins[i];
let d = dist(player.x, player.y, coin.x, coin.y);
if (d < (player.size + coin.size) / 2) {
coins.splice(i, 1); // Remove coin
score++;
}
}
// Display score
fill(0);
textAlign(LEFT);
text("Score: " + score, 10, 30);
// Move player
player.x = mouseX;
player.y = mouseY;
}
Solid Walls (Stop Movement)
let player = { x: 100, y: 200, w: 40, h: 40 };
let wall = { x: 200, y: 150, w: 20, h: 100 };
let speed = 3;
function draw() {
background(220);
// Store old position
let oldX = player.x;
let oldY = player.y;
// Move player
if (keyIsDown(LEFT_ARROW)) player.x -= speed;
if (keyIsDown(RIGHT_ARROW)) player.x += speed;
if (keyIsDown(UP_ARROW)) player.y -= speed;
if (keyIsDown(DOWN_ARROW)) player.y += speed;
// Check collision with wall
if (player.x < wall.x + wall.w &&
player.x + player.w > wall.x &&
player.y < wall.y + wall.h &&
player.y + player.h > wall.y) {
// Collision! Restore old position
player.x = oldX;
player.y = oldY;
}
// Draw
fill(100);
rect(wall.x, wall.y, wall.w, wall.h);
fill(100, 150, 250);
rect(player.x, player.y, player.w, player.h);
}
Enemy Collision (Take Damage)
let player = { x: 200, y: 200, size: 40, health: 100 };
let enemy = { x: 300, y: 250, size: 35 };
let lastHit = 0;
let hitCooldown = 1000; // 1 second between hits
function draw() {
background(220);
// Draw player (color based on health)
if (player.health > 50) {
fill(100, 150, 250);
} else {
fill(250, 100, 100);
}
circle(player.x, player.y, player.size);
// Draw enemy
fill(255, 0, 0);
circle(enemy.x, enemy.y, enemy.size);
// Check collision
let d = dist(player.x, player.y, enemy.x, enemy.y);
if (d < (player.size + enemy.size) / 2) {
// Only take damage once per cooldown period
if (millis() - lastHit > hitCooldown) {
player.health -= 10;
lastHit = millis();
}
}
// Display health
fill(0);
textAlign(LEFT);
text("Health: " + player.health, 10, 30);
// Game over
if (player.health <= 0) {
textAlign(CENTER);
textSize(48);
text("GAME OVER", 200, 200);
noLoop();
}
// Move player
player.x = mouseX;
player.y = mouseY;
}
Optimization Tips
Only Check Nearby Objects
For many objects, check distance first:
// Quick distance check before expensive collision
let quickDist = abs(obj1.x - obj2.x) + abs(obj1.y - obj2.y);
let maxDist = obj1.size + obj2.size;
if (quickDist < maxDist * 1.5) {
// Only do precise collision if nearby
if (preciseCollisionCheck(obj1, obj2)) {
// Handle collision
}
}
Spatial Grid
For hundreds of objects, divide space into grid:
// Advanced technique - divides canvas into regions
// Only check collisions within same or adjacent regions
Tips & Tricks
- Circle collision - Simplest and fastest method
- Store old position - Makes it easy to undo movement on collision
- Cooldown timers - Prevent damage every single frame
- Visual feedback - Flash or color change when hit
- Debug drawing - Draw collision shapes to test
- Hitboxes - Can be smaller than visual size (more forgiving)
Common Gotchas
⚠️ Size vs Radius - Remember: radius = diameter / 2
⚠️ AABB only works for axis-aligned rectangles - Rotated rectangles need different method
⚠️ Removing from arrays - Loop backwards when removing items
⚠️ Continuous damage - Use cooldown timers to space out damage
⚠️ Floating point precision - Use < not === for collision checks
Collision Detection Summary
| Shape Combination | Method | Difficulty |
|---|---|---|
| Circle-Circle | Distance | Easy |
| Rectangle-Rectangle | AABB | Easy |
| Point-Circle | Distance | Easy |
| Point-Rectangle | Bounds check | Easy |
| Circle-Rectangle | Closest point | Medium |
| Rotated shapes | SAT or other | Hard |
Related p5.js Functions
dist()- Calculate distance between pointsconstrain()- Keep value within rangeabs()- Absolute value (for quick distance)millis()- Current time in millisecondscollideCircleCircle()- p5.collide2D library function
Advanced: p5.collide2D Library
For complex collisions, use the p5.collide2D library:
// Add library in index.html
// <script src="https://cdn.jsdelivr.net/npm/p5.collide2d"></script>
// Then use built-in functions:
collideCircleCircle(x1, y1, d1, x2, y2, d2);
collideRectRect(x1, y1, w1, h1, x2, y2, w2, h2);
collidePointCircle(x, y, cx, cy, d);
// ... and many more!
Try It Yourself
Experiment with these ideas:
- Create a coin collection game
- Make a maze with solid walls
- Build a simple shooting game with bullet collision
- Create a platformer with ground collision
- Make enemies that damage the player on touch
Ready to add randomness to your games? Check out the Random & Noise guide! 🎲