Saturday, August 1, 2009

Isometric Tile Hit Testing (Part 2)

And so from part one of the same article we knew how a given tile centroid in screen coordinates P(x,y) is mapped to the corresponding tile in map coordinates M(x,y). It is relatively easier to find the nearest centroid from the mouse cursor position, and here's how.

When user clicks anywhere on the canvas, mouse cursor position is captured relative to the top-left corner of the canvas. The nearest columns of dots to the left and right of cursor position are referred to as "left band" and "right band" respectively (click to enlarge):



The left and right bands can be computed as follow:


double half_canvas_width = canvas_width * 0.5;
double click_x = mouse_x - half_canvas_width - offset;

int factor_x = (int)Math.Floor(click_x / half_tile_width);
int left_band_x = factor_x * half_tile_width;
int right_band_x = (factor_x + 1) * half_tile_width;


Variable offset represents difference between the tip of origin tile M(0,0) and the middle-top of the Content Canvas. Value of offset is zero for square maps, but not for rectangular ones (see Isometric Tile Positioning on Canvas for more details on offset):

Now determine the "even column" between these two bands: the "origin column", and every alternate column are "even columns". For the above case, the "right band" is an even column, while the "left band" is an odd column.

Next, try to identify two neighbouring points on the even column (right band in this scenario), referred to as beta and alpha points (as illustrated in above image):

double click_y = mouse_y - half_tile_height;
int factor_y = (int)Math.Floor(click_y / tile_height);
int beta_y = factor_y * tile_height;
int alpha_y = (factor_y + 1) * tile_height;

After both alpha and beta points are identified, find out which one is closer to click_y (for this case it is alpha point).

Gamma point is vertically centered between alpha and beta points, located across on the odd column. The key to identifying the clicked tile lies on finding the smallest distance from mouse position to either alpha or gamma points.


If Gx+Gy is smaller than Ax+Ay, then gamma point is clicked, otherwise alpha point is clicked.