Picking the 'top' tile in isometric games (images included)

I’ve recently written a small isometric game renderer, which for all intents and purposes seems to work fine.

However, when it comes to ‘picking’ the tile under the mouse cursor, I’m encountering some issues.

When hovering the mouse over a tile in the scene, it seems to pick that tile’s coordinate fine. I then render a ‘selection box’ over the top-most tile at that coordinate:

However, when I extrude the terrain upwards, I can’t quite work out how to make this picking algorithm work beyond just one layer, leading to the wrong tiles getting picked under the mouse cursor:

The way the world is built is by having a 2D array of integers that determine the ‘height’ of the column of tiles at that coordinate. So cell 0,0 might have a height of 6 tiles, and cell 3,4 might have a height of 7 tiles. When rendered, each vertical column of tiles is drawn from back-to-front.

Here’s my current picking code:



// mx: The X coordinate of the mouse (in the world, offset by the camera X position)
// my: The Y coordinate of the mouse (in the world, offset by the camera Y position)
// hoverCell: A Point object storing the hovered-over (2D) world coordinate
// tileRenderSize...: These values represent the width, height (and half widths / heights) of the tiles in the scene

private void getHoverTile()
	{
		int mx = (int)((Mouse.getX() + camX) - tileRenderSizeWidthHalf);
		int my = (int)((Engine.DISPLAY_HEIGHT - Mouse.getY()) + camY);
		
		hoverCell.x = (int)(mx / tileRenderSizeWidthHalf + my / tileRenderSizeHeightHalf) / 2;
		hoverCell.y = (int)(my / tileRenderSizeHeightHalf -(mx / tileRenderSizeWidthHalf)) / 2;
		
		// bounds check
		if (hoverCell.x < 0) hoverCell.x = 0;
		if (hoverCell.x > width-1) hoverCell.x = width-1;
		if (hoverCell.y < 0) hoverCell.y = 0;
		if (hoverCell.y > depth-1) hoverCell.y = depth-1;
	}

Would anybody be able to shed any light on how I can effectively pick the right tile on ‘top’ of each column of tiles? At the moment it only works for one layer! :frowning:

Thanks in advance for any advice anyone can offer!
~Pixel

The “easy” solution is to draw a pick buffer. That is, an image which uses the same rendering process as the buffer you render to screen, except that instead of using the stone, earth, etc. textures it uses a different solid colour for each tile. Then the picking just comes down to a look-up in the pick buffer.

The other approach you could consider is to modify your current code to use a suitable loop. I think the standard approach is to loop from the back to the front testing whether the current tile is under the mouse. In your case, though, it might work better to have a loop something like

Tile tile = null;
for (int h = minHeight; h <= maxHeight; h++) {
	Tile layerTile = getHoverTile(h);
	if (layerTile.height() == h) tile = layerTile;
}

Blimey, that’s genius! I’d never have thought of it like that!

It actually makes perfect sense now - when I draw the tiles to the screen, once I hit the top-most tile in a column I can simply run a quick hit-test to see if the mouse is within it’s ‘face’ area. If so I can mark that as the currently ‘hovered’ tile.

It seems a bit dirty doing this in the render loop, so I guess I could do defer this to the update cycle and do a ‘fake render’ of just the top-tiles (i.e. calculate their positions as I would pre-rendering), then do the hit-test then. This would also serve the benefit of preserving the back-to-front calculation to ensure the front-most tile gets picked over those behind it.

This was a fantastic suggestion to offer up, you’re totally on the money!

Thanks a bundle!