Isometric Depth Sorting — The Problem Nobody Warns You About

It Looks Simple Until It Isn't

Isometric projection seems straightforward: tiles go on a diamond grid, objects draw back-to-front. Sort by mapX + mapY and you're done.

Except you're not. Because then you add:

Each of these breaks the naive sort in a different way.

The Depth Sort Formula

For a pure tile-based game, the depth key is indeed mapX + mapY. Items at higher sums are "closer" to the camera in isometric space and should draw later (on top).

entries.sort((a, b) -> 
    Integer.compare(a.mapX + a.mapY, b.mapX + b.mapY));

This works perfectly for 1×1 items on different tiles. It falls apart for multi-tile furniture because the origin tile (top-left) doesn't represent the visual footprint.

Multi-Tile Furniture

A 2×3 desk at position (2, 4) occupies tiles (2,4), (2,5), (2,6), (3,4), (3,5), (3,6). Its depth should be based on its bottom-right corner — the closest point to the camera — not its origin.

The fix: use mapX + mapY + tileWidth + tileHeight - 2 as the depth key for furniture.

Stacking: The Visual Offset Problem

When you place 5 gold ingots on the same tile, they all have the same depth key and the same screen position. Without intervention, they render exactly on top of each other — one visible ingot instead of five.

The solution is a stackIndex per item: the Nth stackable item on a tile draws with a vertical offset of stackIndex * itemHeight * overlapFactor.

int stackShift = 0;
if (furniture.stackable && furniture.stackIndex > 0) {
    stackShift = (int)(furniture.stackIndex * drawH * STACK_OVERLAP);
}
g2d.drawImage(image, posX, posY - stackShift, drawW, drawH, null);

The overlapFactor (0.15–0.65) controls how much each item peeks above the one below. Lower values = tighter stacking.

Background Items: The Two-Pass Solution

Floor rugs and carpets should render below everything, including the tile highlight overlay. But they're still "furniture" in the data model.

The solution is a two-pass render:

  1. Pass 1: Draw tiles, then background furniture (sorted)
  2. Pass 2: Draw standing furniture interleaved with players (sorted)

A background boolean flag on each furniture item determines which pass handles it.

The Interaction With Pathfinding

Depth sorting is purely visual, but it creates an expectation: if item A renders behind item B, clicking on the overlap region should select B (the frontmost).

This means hit-testing must mirror the render order — iterate in reverse depth order and return the first non-transparent pixel match. If you sort differently for rendering vs. hit-testing, users will click on visually hidden items.

Lessons

Isometric rendering is a masterclass in how simple rules create complex interactions. Every feature you add — stacking, multi-tile, background layers, players — creates a new edge case in the sort order.

The key insight: render order is not a single sort. It's a multi-pass pipeline where each pass has its own rules. Trying to solve everything with one comparator leads to bugs that only appear with specific furniture arrangements.

#isometric#rendering#java#algorithms