In isometric games, rendering order is crucial. Objects closer to the camera should appear in front of objects further away. This is where Y-sorting comes in—it ensures that when drawing sprites, the objects in the back are rendered first, and those in the front are drawn last. Without proper Y-sorting, objects can overlap incorrectly, breaking the illusion of depth.
For simple cases, a common sorting method is: y-sort value= x + y
This works well in many situations but starts to fall apart when dealing with buildings or larger objects that span multiple tiles. One the issues is visible below where 3×5 Building y sorting on one side is incorrect.

Additionally, I’ve been working on Y-sorting for NPCs moving around a 5×3 building, and I’ve hit an issue where sometimes but not always they are hidden around the corners. In the attached screenshot, you can see a 2D representation of the scene.

Desired rendering order:
1. Grey NPCs (behind the building)
2. The building itself
3. Green NPCs (in front of the building)
The purple arrow represents the camera’s viewing direction. The sorting value is currently calculated using x + y, but there’s a problem:
The dashed-line NPCs on both sides of the building end up with the same Y-sort value as the building itself. This causes them to be rendered at the wrong depth—sometimes appearing in front when they should be behind, and vice versa.
At first, I thought I could tweak the Y-sorting formula by adjusting x or y values (e.g., dividing by 2), but that solution falls apart when the building is rotated from 5×3 to 3×5. The formula needs to be consistent for NPCs, though I can use a different sorting method for buildings.
So the challenge is: how do I ensure that NPCs behind the building get a lower Y-sort value than NPCs in front, without breaking when the building rotates?
After some testing, I found a simple yet effective solution: adjusting the Y-sorting value at the building’s corners.
Instead of treating the entire building as a single tile with a fixed Y-sort value, I applied a slight offset to the corners. This ensures that NPCs behind the building get a slightly lower sort value, and those in front get a slightly higher one. The result? The rendering order is now correct, and NPCs no longer appear in front of buildings when they shouldn’t.
Here’s the adjusted sorting formula: y-sort value= x + y + corner offset
The corner offset is a small adjustment added only at specific points of the building’s footprint. This pushes the sorting values of NPCs in front slightly higher while keeping those behind lower. This method is great because:
– It works regardless of building orientation (whether the building is 5×3 or 3×5).
– It doesn’t require modifying the NPC sorting logic—only the building’s sorting.
– It’s lightweight and doesn’t require extra complex calculations.

In the above code, there are two key adjustments.
1. Adjusting Y-Sorting for Large Tiles (Buildings)
adj = self.w if self.w < self.h else self.h
f = (self.grid_pos[0] + self.grid_pos[1]) - adj
If the object (e.g., a building) spans multiple tiles, an adjustment value (adj) is calculated based on its dimensions. The smaller dimension (w or h) is used as the adjustment factor.
This adjustment lowers the Y-sorting value for larger tiles, ensuring that NPCs behind the building are rendered first.
2. Using Precomputed Base Y-Sorting Values
f = (self.grid_pos[0] + self.grid_pos[1]) + self.world.base_y_sort_values[self.grid_pos[0]][self.grid_pos[1]]
Instead of relying purely on x + y, the code retrieves a precomputed Y-sorting adjustment from self.world.base_y_sort_values.
This means each tile can have a custom Y-sorting offset, allowing fine control over how buildings or objects are layered.

This adjustment comes from a precomputed lookup table, which ensures corner offsets are consistently applied without recalculating them every frame.