Skip to main content

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 points
  • minDist - 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:
    1. Player's left edge is left of box's right edge
    2. Player's right edge is right of box's left edge
    3. Player's top edge is above box's bottom edge
    4. 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

  1. Circle collision - Simplest and fastest method
  2. Store old position - Makes it easy to undo movement on collision
  3. Cooldown timers - Prevent damage every single frame
  4. Visual feedback - Flash or color change when hit
  5. Debug drawing - Draw collision shapes to test
  6. 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 CombinationMethodDifficulty
Circle-CircleDistanceEasy
Rectangle-RectangleAABBEasy
Point-CircleDistanceEasy
Point-RectangleBounds checkEasy
Circle-RectangleClosest pointMedium
Rotated shapesSAT or otherHard
  • dist() - Calculate distance between points
  • constrain() - Keep value within range
  • abs() - Absolute value (for quick distance)
  • millis() - Current time in milliseconds
  • collideCircleCircle() - 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! 🎲