Game Development 15 min read

Master 2D Collision Detection: From Bounding Boxes to SAT

This article explains common 2D collision‑detection techniques—including axis‑aligned bounding boxes, circle checks, grid partitioning, pixel‑level tests, ray casting, and the Separating Axis Theorem—detailing their concepts, algorithms, code examples, advantages, drawbacks, and typical use cases for game development.

Aotu Lab
Aotu Lab
Aotu Lab
Master 2D Collision Detection: From Bounding Boxes to SAT

Axis-Aligned Bounding Box (AABB)

Concept: Detect collision between two non‑rotated rectangles by testing whether their edges overlap.

rect1.x < rect2.x + rect2.width &&
rect1.x + rect1.width > rect2.x &&
rect1.y < rect2.y + rect2.height &&
rect1.y + rect1.height > rect2.y

Drawbacks:

Only works for axis‑aligned rectangles; rotation is not supported.

Precision suffers when the rectangle contains transparent or patterned regions.

Fast‑moving objects may tunnel between frames and miss collisions.

Typical use case: Collision between rectangular game objects.

Circle Collision

Concept: Two circles collide when the distance between their centers is less than the sum of their radii.

Math.sqrt(Math.pow(circleA.x - circleB.x, 2) +
          Math.pow(circleA.y - circleB.y, 2)) <
      circleA.radius + circleB.radius

Drawbacks: Similar limitations to AABB when circles are approximated by bounding boxes.

Typical use case: Collision of spherical objects such as balls.

Map Grid Partitioning

Concept: Divide the game world into a grid; each object records the cell it occupies. Collision is checked only between objects in the same or neighboring cells. All colliding objects must fit within a cell or an integer multiple of a cell.

map = [
  [0,0,1,1,1,0,0,0,0],
  [0,1,1,0,0,1,0,0,0],
  [0,1,0,0,0,0,1,0,0],
  [0,1,0,0,0,0,1,0,0],
  [0,1,1,1,1,1,1,0,0]
];

player = { left: 2, top: 2 };
// movement logic checks the next cell before moving

Drawbacks: Limited to scenarios where object size matches grid granularity.

Typical use case: Tile‑based games such as Sokoban or Minesweeper.

Pixel‑Level Detection

Concept: Determine overlap by examining each pixel of two objects on an off‑screen canvas.

Render both objects to separate off‑screen canvases and compare pixel opacity at identical coordinates.

Use globalCompositeOperation = 'destination-in' to keep only overlapping pixels; non‑transparent pixels indicate a collision.

Note: The first method requires two off‑screen canvases, the second only one.

Drawbacks: High computational cost because every pixel must be examined.

Typical use case: Precise collision checks where visual fidelity matters.

Ray Casting

Concept: Cast a line along an object's velocity vector and another line from a second object; if the intersection lies within the target area, a collision is reported.

Example: Throwing a ball into a bucket – draw line #1 along the ball’s velocity, draw line #2 from the bucket edge, and test the intersection point.

Advantages: Works well for fast‑moving objects.

Drawbacks: Applicable only to limited scenarios.

Typical use case: Projectile‑into‑target checks.

Separating Axis Theorem (SAT)

Concept: For any two convex polygons, project them onto each potential separating axis (normals of edges). If a gap exists on any axis, the polygons do not intersect; otherwise they collide.

function polygonsCollide(polygon1, polygon2) {
    var axes = polygon1.getAxes();
    axes.push.apply(axes, polygon2.getAxes());
    for (var i = 0; i < axes.length; i++) {
        var axis = axes[i];
        var projection1 = polygon1.project(axis);
        var projection2 = polygon2.project(axis);
        if (!projection1.overlaps(projection2)) {
            return false;
        }
    }
    return true;
}

Key steps:

Determine edge vectors for each polygon.

Compute a perpendicular (normal) vector for each edge and normalize it to obtain the projection axis.

Project all vertices onto the axis, recording the minimum and maximum scalar values.

Check whether the intervals overlap; a non‑overlap on any axis means no collision.

Supporting classes:

// Vector class
function Vector(x, y) {
    this.x = x;
    this.y = y;
}
Vector.prototype = {
    getMagnitude: function() {
        return Math.sqrt(this.x * this.x + this.y * this.y);
    },
    dotProduct: function(v) {
        return this.x * v.x + this.y * v.y;
    },
    subtract: function(v) {
        return new Vector(this.x - v.x, this.y - v.y);
    },
    edge: function(v) {
        return this.subtract(v);
    },
    perpendicular: function() {
        return new Vector(this.y, -this.x);
    },
    normalize: function() {
        var m = this.getMagnitude();
        return m !== 0 ? new Vector(this.x / m, this.y / m) : new Vector(0, 0);
    },
    normal: function() {
        return this.perpendicular().normalize();
    }
};

// Projection class
function Projection(min, max) {
    this.min = min;
    this.max = max;
}
Projection.prototype = {
    overlaps: function(p) {
        return this.max > p.min && p.max > this.min;
    }
};

// Project a polygon onto an axis
function project(polygon, axis) {
    var scalars = [];
    polygon.points.forEach(function(point) {
        var v = new Vector(point.x, point.y);
        scalars.push(v.dotProduct(axis));
    });
    return new Projection(Math.min.apply(Math, scalars), Math.max.apply(Math, scalars));
}

Advantages: Precise detection for any convex polygon and circles (by treating a circle as a polygon with many edges).

Drawbacks: Not suitable for concave polygons.

Typical use case: Collision between arbitrary convex shapes and circles.

Collision Performance Optimisation

Testing every pair of objects each frame is wasteful. Most engines split collision handling into two phases:

Broad Phase

Provides a shortlist of potentially colliding entities using spatial data structures such as Quad‑Trees, R‑Trees, or spatial hash maps.

Narrow Phase

Applies precise algorithms (AABB, circle, SAT, pixel, etc.) to the shortlist to confirm actual collisions.

Minimum Translation Vector (MTV)

When two objects remain intersecting after a collision, the Minimum Translation Vector separates them by the smallest possible displacement.

References

https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection

https://example.com/html5-canvas-core-techniques

collision detectionray castingSATpixel detectiongame physics2D gamesbounding box
Aotu Lab
Written by

Aotu Lab

Aotu Lab, founded in October 2015, is a front-end engineering team serving multi-platform products. The articles in this public account are intended to share and discuss technology, reflecting only the personal views of Aotu Lab members and not the official stance of JD.com Technology.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.