# How can I cull non-visible isometric tiles?

I have a problem which I am struggling to solve. I have a large map of around 100x100 tiles which form an isometric map. The user is able to move the map around by dragging the mouse. I am trying to optimize my game only to draw the visible tiles.

So far my code is like this. It appears to be ok in the x direction, but as soon as one tile goes completely above the top of the screen, the entire column disappears. I am not sure how to detect that all of the tiles in a particular column are outside the visible region.

    double maxTilesX = widthOfScreen/ halfTileWidth + 4;
double maxTilesY = heightOfScreen/ halfTileHeight + 4;

int rowStart = Math.max(0,( -xOffset / halfTileWidth)) ;
int colStart = Math.max(0,( -yOffset / halfTileHeight));

rowEnd = (int) Math.min(mapSize, rowStart + maxTilesX);
colEnd = (int) Math.min(mapSize, colStart + maxTilesY);


EDIT - I think I have solved my problem, but perhaps not in a very efficient way. I have taken the center of the screen coordinates, determined which tile this corresponds to by converting the coordinates into cartesian format. I then update the entire box around the screen.

• You should probably focus on culling individual tiles instead of entire rows or columns. Nov 8, 2011 at 16:58
• I thought about this. But I'm not sure whether or not the cost associated with finding out if a tile is absolutely inside will make it worthwhile. Perhaps this is something I will try! :) Nov 8, 2011 at 17:00
• "But I'm not sure"... try it and find out! :) I have a tile map, admittedly not isometric, that's bigger than 500x500 and my draw call only loops through the tiles on screen based on the camera's position in world coordinates. I always imagine isometric tiles as just square tiles where every other row is offset by half a tile to the right (or left). Though maybe your drawing routine doesn't work like that. Nov 8, 2011 at 17:11

The method you are using in your question is the way I have also done culling for my isometric game (personally I think the best way to cull an isometric map, would be interested in other ways though). To go into some of the specifics, this is how I solved the same problem.

My main drawing loop looked something like:

for (int y = yMin; y <= yMax; y++)
{
for (int x = xMin; x <= xMax; x++)
{
//drawing here using x and y as index on arrays
}
}


Before this is called, I updated my xMax and yMax which was based on camera location, zoom and resolution of the screen. midTile.X and midTile.Y are the rows and columns values of the centre tile (starting point). Then half the screen resolution is then divided by number of tiles (rows or columns) between the centre tile and the edge of the screen to a distance in tiles from the centre tile. Zoom is taken into account if needed to scale.

 midTile = GetCentreTile(gameCamera);
xMax = (int)(midTile.X + Math.Round((HalfScreenResX / (TileWidth / 2)) / Zoom));
xMin = (int)(midTile.X - Math.Round((HalfScreenResX / (TileWidth / 2)) / Zoom));
yMax = (int)(midTile.Y + Math.Round((HalfScreenResY / (TileHeight / 2)) / Zoom));
yMin = (int)(midTile.Y - Math.Round((HalfScreenResY / (TileHeight / 2)) / Zoom));


Personally I render the map with an offset by 1X to make other calculations easier, so in this case you'll want to compensate by + 1 on the rows (X) that you are dividing the screen resolution by.

Also a good idea to make sure your values are valid inside the map to avoid invalid index array problems.

xMin = xMin >= 0 ? xMin : 0;
xMax = xMax <= map.Width - 1 ? xMax : map.Width - 1;
yMin = yMin >= 0 ? yMin : 0;
yMax = yMax <= map.Height - 1 ? yMax : map.Height - 1;


I've found this method to be more efficient than checking every tile's visible property, also, isometric drawing order is very important once to get to objects walking 'behind' and 'in-front' of other objects you are rendering associated with tiles on your map.

Hope this helped.

The bug is not in the code you've shown us.

Anyway, your tile drawing loop should look something like this pseudocode:

for each row from rowStart to rowEnd do:
for each col from colStart to colEnd do:
draw tile at row,col;
end
end


I'd guess that you're doing something else, and that this is causing the bug. Perhaps if you actually showed us that code...

(Ps. All of this assumes that your rows are in fact shown horizontally and your columns vertically on the screen. If you're storing your map so that your rows and columns actually look diagonal on the screen, the math gets a bit more complicated.)

• yup my drawing loop is similar to that. I am storing my map so the rows look diagonal on the screen though. To be honest, it sounds as if doing it the other way will give better performance once the array has been filled Nov 8, 2011 at 20:21