Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to transform mouse location in isometric tiling map?

Tags:

algorithm

math

So I've managed myself to write the first part (algorithm) to calculate each tile's position where should it be placed while drawing this map (see bellow). However I need to be able to convert mouse location to the appropriate cell and I've been almost pulling my hair off because I can't figure out a way how to get the cell from mouse location. My concern is that it involves some pretty high math or something i'm just something easy i'm not capable to notice.
For example if the mouse position is 112;35 how do i calculate/transform it to to get that the cell is 2;3 at that position? Maybe there is some really good math-thinking programmer here who would help me on this or someone who knows how to do it or can give some information?

enter image description here

var cord:Point = new Point();
cord.x = (x - 1) * 28 + (y - 1) * 28;
cord.y = (y - 1) * 14 + (x - 1) * (- 14);

Speaking of the map, each cell (transparent tile 56x28 pixels) is placed in the center of the previous cell (or at zero position for the cell 1;1), above is the code I use for converting cell-to-position. I tried lot of things and calculations for position-to-cell but each of them failed.

Edit: After reading lot of information it seems that using off screen color map (where colors are mapped to tiles) is the fastest and most efficient solution?

like image 1000
Rihards Avatar asked Aug 02 '11 16:08

Rihards


4 Answers

I know this is an old post, but I want to update this since some people might still look for answers to this issue, just like I was earlier today. However, I figured this out myself. There is also a much better way to render this so you don't get tile overlapping issues.

The code is as simple as this:

mouse_grid_x = floor((mouse_y / tile_height) + (mouse_x / tile_width));
mouse_grid_y = floor((-mouse_x / tile_width) + (mouse_y / tile_height));

mouse_x and mouse_y are mouse screen coordinates.

tile_height and tile_width are actual tile size, not the image itself. As you see on my example picture I've added dirt under my tile, this is just for easier rendering, actual size is 24 x 12. The coordinates are also "floored" to keep the result grid x and y rounded down.

Also notice that I render these tiles from the y=0 and x=tile_with / 2 (red dot). This means my 0,0 actually starts at the top corner of the tile (tilted) and not out in open air. See these tiles as rotated squares, you still want to start from the 0,0 pixel.

Tiles will be rendered beginning with the Y = 0 and X = 0 to map size. After first row is rendered you skip a few pixels down and to the left. This will make the next line of tiles overlap the first one, which is a great way to keep the layers overlapping coorectly. You should render tiles, then whatever in on that tile before moving on to the next.

I'll add a render example too:

for (yy = 0; yy < map_height; yy++)
{
     for (xx = 0; xx < map_width; xx++)
     {
          draw tiles here with tile coordinates:
          tile_x = (xx * 12) - (yy * 12) - (tile_width / 2)
          tile_y = (yy * 6) + (xx * 6)

          also draw whatever is on this tile here before moving on
     }
}

Isometric Image

like image 120
Ernst Albrigtsen Avatar answered Nov 04 '22 22:11

Ernst Albrigtsen


(1) x` = 28x -28 + 28y -28  = 28x + 28y -56
(2) y` = -14x +14 +14y -14 = -14x + 14y

Transformation table:

[x] [28  28 -56 ] = [x`]
[y] [-14 14  0  ]   [y`]
[1] [0    0  1  ]   [1 ]

[28  28 -56 ] ^ -1 
[-14 14  0  ]
[0    0  1  ] 

Calculate that with a plotter ( I like wims )

[1/56 -1/28  1 ]
[1/56  1/28  1 ]
[0      0    1 ]

x = 1/56*x` - 1/28y` + 1
y = 1/56*x` + 1/28y` + 1
like image 26
Yochai Timmer Avatar answered Nov 04 '22 21:11

Yochai Timmer


enter image description here

I rendered the tiles like above.

the sollution is VERY simple!

first thing:

my Tile width and height are both = 32 this means that in isometric view, the width = 32 and height = 16! Mapheight in this case is 5 (max. Y value)

y_iso & x_iso == 0 when y_mouse=MapHeight/tilewidth/2 and x_mouse = 0

when x_mouse +=1, y_iso -=1

so first of all I calculate the "per-pixel transformation"

TileY = ((y_mouse*2)-((MapHeight*tilewidth)/2)+x_mouse)/2;

TileX = x_mouse-TileY;

to find the tile coordinates I just devide both by tilewidth

TileY = TileY/32; TileX = TileX/32;

DONE!! never had any problems!

like image 4
Tijgerd Avatar answered Nov 04 '22 21:11

Tijgerd


I've found algorithm on this site http://www.tonypa.pri.ee/tbw/tut18.html. I couldn't get it to work for me properly, but I change it by trial and error to this form and it works for me now.

int x = mouse.x + offset.x - tile[0;0].x; //tile[0;0].x is the value of x form witch map was drawn
int y = mouse.y + offset.y;
double _x =((2 * y + x) / 2);
double _y= ((2 * y - x) / 2);
double tileX = Math.round(_x / (tile.height - 1)) - 1;
double tileY = Math.round(_y / (tile.height - 1));

This is my map generation

for(int x=0;x<max_X;x++)
for(int y=0;y<max_Y;y++)
map.drawImage(image, ((max_X - 1) * tile.width / 2) - ((tile.width - 1) / 2 * (y - x)), ((tile.height - 1) / 2) * (y + x));
like image 1
Dawid Avatar answered Nov 04 '22 21:11

Dawid