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):
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
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}
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:
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:
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:
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:
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