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.

4 comments:

Marcus said...

Nice work! Is there any downloadable sourcecode for this? I am currently trying to figure out what the best approch for a Isometric Silverlight Control would possible be and am a little lost ...

Captain said...

Thanks for the nice word, Marcus. I was developing this when I wrote the article. It was part of something bigger I'm developing but unfortunately it is not complete as of now because I need to shift to another area of that "bigger thing", and the codes are not readily sharable. Feel free to ask me any questions you have, I'm sure I can also learn a thing or two while talking to you. Please do not hesitate!

Marcus said...

For me it currently boils down to the questions which controls to use.

The basic two routes that would come to my mind are:

- Using the "usual" rendering approach via WriteableBitmap. This would mean I have to draw the gamefield myself.

- Using a canvas and place entities as controls on it.

It seems to me that you are going for the second approach. And this is also the one I would prefer!

But this is where the trouble starts: I am currently approaching my canvas control via a RotateTransform and am struggling on the HitTesting.

I haven't applied your techniques by now, but I would be interested in your "lowlevel" (= used controls) implementation.

Captain said...

Hi Marcus, sorry it took me a while to respond. I do not yet have anything readily sharable right now. In fact my iso codes have not been run for nearly five months now (due to me being very busy with other stuff...).

Stay tuned, I may have more to share in near future :)