collision detection
java programming
rectangle collision
game development
2D graphics

Collision detection between two rectangles in java

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Axis-Aligned Bounding Box (AABB) collision detection checks whether two rectangles overlap by comparing their edges. Two rectangles collide if and only if they overlap on both the x-axis and the y-axis. This runs in O(1) time and is the foundation of 2D collision detection in games and UI frameworks.

The AABB Overlap Condition

Two rectangles A and B overlap when all four of these conditions are true:

  • A's left edge is to the left of B's right edge
  • A's right edge is to the right of B's left edge
  • A's top edge is above B's bottom edge
  • A's bottom edge is below B's top edge

In code (where y increases downward, as in most screen coordinate systems):

java
1boolean collides =
2    a.x < b.x + b.width &&
3    a.x + a.width > b.x &&
4    a.y < b.y + b.height &&
5    a.y + a.height > b.y;

If any one condition is false, the rectangles do not overlap.

Basic Implementation

java
1public class Rectangle {
2    public double x, y, width, height;
3
4    public Rectangle(double x, double y, double width, double height) {
5        this.x = x;
6        this.y = y;
7        this.width = width;
8        this.height = height;
9    }
10
11    public boolean intersects(Rectangle other) {
12        return this.x < other.x + other.width &&
13               this.x + this.width > other.x &&
14               this.y < other.y + other.height &&
15               this.y + this.height > other.y;
16    }
17}
java
1Rectangle player = new Rectangle(100, 100, 50, 50);
2Rectangle enemy = new Rectangle(130, 120, 40, 40);
3
4if (player.intersects(enemy)) {
5    System.out.println("Collision detected!");
6}

Using java.awt.Rectangle

Java's standard library provides java.awt.Rectangle with built-in collision detection:

java
1import java.awt.Rectangle;
2
3Rectangle r1 = new Rectangle(100, 100, 50, 50);
4Rectangle r2 = new Rectangle(130, 120, 40, 40);
5
6// Check for intersection
7if (r1.intersects(r2)) {
8    System.out.println("Collision!");
9}
10
11// Get the overlapping region
12Rectangle overlap = r1.intersection(r2);
13System.out.println("Overlap area: " + overlap.width * overlap.height);
14
15// Check if one rectangle contains another
16if (r1.contains(r2)) {
17    System.out.println("r1 fully contains r2");
18}

Using Rectangle2D for Floating-Point Precision

For sub-pixel precision, use Rectangle2D.Double:

java
1import java.awt.geom.Rectangle2D;
2
3Rectangle2D.Double r1 = new Rectangle2D.Double(100.5, 100.5, 50.0, 50.0);
4Rectangle2D.Double r2 = new Rectangle2D.Double(130.2, 120.8, 40.0, 40.0);
5
6if (r1.intersects(r2)) {
7    System.out.println("Collision with sub-pixel precision");
8}

Game Loop Example

A typical game loop with collision detection:

java
1public class Game {
2    private Rectangle player;
3    private List<Rectangle> obstacles;
4
5    public void update() {
6        // Move player based on input
7        player.x += velocityX;
8        player.y += velocityY;
9
10        // Check collisions with all obstacles
11        for (Rectangle obstacle : obstacles) {
12            if (player.intersects(obstacle)) {
13                handleCollision(player, obstacle);
14            }
15        }
16    }
17
18    private void handleCollision(Rectangle a, Rectangle b) {
19        // Calculate overlap on each axis
20        double overlapX = Math.min(a.x + a.width, b.x + b.width)
21                        - Math.max(a.x, b.x);
22        double overlapY = Math.min(a.y + a.height, b.y + b.height)
23                        - Math.max(a.y, b.y);
24
25        // Push back on the axis with less overlap (minimum translation)
26        if (overlapX < overlapY) {
27            if (a.x < b.x) a.x -= overlapX;
28            else a.x += overlapX;
29        } else {
30            if (a.y < b.y) a.y -= overlapY;
31            else a.y += overlapY;
32        }
33    }
34}

Optimization: Broad Phase with Spatial Partitioning

When checking many objects, testing every pair is O(n²). Use spatial partitioning to reduce checks:

java
1// Simple grid-based broad phase
2public class SpatialGrid {
3    private int cellSize;
4    private Map<Long, List<Rectangle>> cells = new HashMap<>();
5
6    public SpatialGrid(int cellSize) {
7        this.cellSize = cellSize;
8    }
9
10    private long cellKey(int cx, int cy) {
11        return ((long) cx << 32) | (cy & 0xFFFFFFFFL);
12    }
13
14    public void insert(Rectangle r) {
15        int startX = (int)(r.x / cellSize);
16        int startY = (int)(r.y / cellSize);
17        int endX = (int)((r.x + r.width) / cellSize);
18        int endY = (int)((r.y + r.height) / cellSize);
19
20        for (int cx = startX; cx <= endX; cx++) {
21            for (int cy = startY; cy <= endY; cy++) {
22                cells.computeIfAbsent(cellKey(cx, cy), k -> new ArrayList<>())
23                     .add(r);
24            }
25        }
26    }
27
28    public List<Rectangle> getPotentialCollisions(Rectangle r) {
29        // Return only objects in the same grid cells
30        Set<Rectangle> candidates = new HashSet<>();
31        int startX = (int)(r.x / cellSize);
32        int startY = (int)(r.y / cellSize);
33        int endX = (int)((r.x + r.width) / cellSize);
34        int endY = (int)((r.y + r.height) / cellSize);
35
36        for (int cx = startX; cx <= endX; cx++) {
37            for (int cy = startY; cy <= endY; cy++) {
38                List<Rectangle> cell = cells.get(cellKey(cx, cy));
39                if (cell != null) candidates.addAll(cell);
40            }
41        }
42        candidates.remove(r);
43        return new ArrayList<>(candidates);
44    }
45}

Common Pitfalls

  • Coordinate system: Screen coordinates typically have y increasing downward. Mathematical coordinates have y increasing upward. Make sure your collision conditions match your coordinate system.
  • Edge-touching: The conditions above use strict inequality (<, >), so rectangles that touch edges without overlapping are not considered colliding. Use <= if you want edge-touching to count.
  • Integer overflow: java.awt.Rectangle uses int fields. Very large coordinates or sizes can overflow. Use Rectangle2D.Double for large worlds.
  • Moving objects: Fast-moving objects can pass through thin obstacles between frames (tunneling). For high-speed objects, use swept collision detection or reduce the time step.
  • Rotated rectangles: AABB only works for axis-aligned rectangles. For rotated rectangles, use the Separating Axis Theorem (SAT) instead.

Summary

  • Two axis-aligned rectangles collide when they overlap on both axes — four simple comparisons
  • Use java.awt.Rectangle.intersects() for built-in support or implement your own for custom types
  • Calculate minimum translation vector to resolve collisions by pushing back on the axis with less overlap
  • Use spatial partitioning (grids, quadtrees) when checking many objects to avoid O(n²) pair checks
  • AABB does not handle rotated rectangles — use SAT for that case

Course illustration
Course illustration

All Rights Reserved.