TileMath in DIAMOND isometric 2:1

Started by
5 comments, last by suliman 17 years, 7 months ago
Hi I asked this in another thread and was only send to the tutials several times. But all i found there was how to do it on a straight(non-diamond) world. To clearify, im using a map similar to age of empire/transport tycoon where one courner of the map points upright north and the rest south, west and east. In THIS enviroment, how do i do: -Which tile is my mouse over? (i know the colored tile offset-trick from the tutorial but the rest? -How do I position something that is standing on tile x,y? Given that we have tileW (20) tileH (10) panX/panY (for scrolling the view) 0,0 is far west courner of map Thanks a lot Erik
Advertisement
For "plain" iso 2:1, this is a very simple thing to calculate.

Short answer:

You say tile coords (0,0) are the far west corner of the meaning (left-most onscreen, I assume). Also assuming that the tile x-axis goes up-right from there, and the tile y-axis goes down-right from there, then:

Step 1.
Convert mouse coordinates to screenspace coords (by accounting for the scrolling of the map):

screenX = mouseX + panX
screenY = mouseY + panY

Step 2.
Convert screenspace coords to tilespace coords:
tileX = (screenX / tileW) - (screenY / tileH)
tileY = (screenX / tileW) + (screenY / tileH)

And that's your answer. Note that the tilespace coordinates are exact (eg. [15.87, 8.5]) so you'll need to ROUND DOWN (ie. floor()) if you want to index into an array (eg. [15,8]).

To go the other way, you reverse the process:
screenX = (tileY * 0.5 * tileW) + (tileX * 0.5 * tileW)
screenY = (tileY * 0.5 * tileH) - (tileX * 0.5 * tileH)

mouseX = screenX - panX
mouseY = screenY - panY

And now the ill-named (mouseX, mouseY) coords are the location on the screen of the point.


This seems a relatively common question, despite (in this style at least) being a fairly simple thing to calculate. To work it out for yourself, do this:

1. Draw a diamond on a bit of paper.
2. Label the corners with the tilemap coords. Ie. (0,0) on the left most, (1,0) on the topmost [for the example I used above), etc.
3. Now trace a line horizontally from the leftmost corner to the rightmost. Okay, so you've moved [tilewidth] pixels in the screenspace (or "paperspace" I guess) x-axis, and +1 unit in the tilespace x-axis and +1 unit in the tilespace y-axis. So now you know that for every [tilewidth] pixels along in the screenspace x-axis, you need to increment the tilex and tiley values by one each. So you write:

tileX = 1 * (screenX / tileW)
tileY = 1 * (screenX / tileW)

4. Now do the same from top to bottom. You move +[tileheight] pixels in screenspace y-axis, and -1 on the tilespace x-axis, and +1 on the tilespace y-axis. So you add this to the above equations:

tileX = 1 * (screenX / tileW) + -1 * (screenY / tileH)
tileY = 1 * (screenX / tileW) + 1 * (screenY / tileH)

And there you go. The only step not done there is taking into account scrolling which is simply a matter of adding (panX,panY) to the original screenX, screenY coordinates.

Anyway, I hope that answers your question.

PS. NB that if plug the corners of the screen itself into the above equations (ie. [0,0] [screenWidth,0] etc.) you'll get the coords of the four tiles that form the screen quadrilateral (in tilespace the screen is a rectangle rotated 45 degrees). If you interpolate between in your tile-drawing code, you'll only draw the tiles that are visible, regardless of the size of your actual tilemap. For large tilemaps, this is a crucial fact.
thanks a lot. it seems so easy (now that someone taught me)

It was maybe to simple to be included in the tutorials, but it should nevertheless, especially as there seem to be some confusion between the "two isometric world-types".

Erik
almost got it all to work, but one problem remains:

In the north half of my map, mapPixelY gets negative and it screws up the mouseOverWhichTile routine. Its the mapX/mapY calc that gets messy, but why? Its not division with 0 or anything... ( i tried making an Y-offset of the entire halfHeight, ensuring mapPixelY was never negative, but it still scews up the upper half of the map...)

thanks


float x,y;
hge->Input_GetMousePos(&x,&y);
mouseX=x;
mouseY=y;
mapPixelX=x-panX;
mapPixelY=y-panY;
mapX = (mapPixelX / TILEX) - (mapPixelY / TILEY);
mapY = (mapPixelX / TILEX) + (mapPixelY / TILEY);

int texW = hge->Texture_GetWidth(www.tileTex);
int texPos;

int screenX = (mapY * 0.5 * TILEX) + (mapX * 0.5 * TILEX);
int screenY = (mapY * 0.5 * TILEY) - (mapX * 0.5 * TILEY);

texPos=(texW*(abs(mapPixelY-screenY)))+abs(mapPixelX-screenX);

if(www.tileIndex[texPos]==ARGB(255,0,0,0))
mapY--;
else if(www.tileIndex[texPos]==ARGB(255,255,0,0))
mapX++;
else if(www.tileIndex[texPos]==ARGB(255,0,255,0))
mapX--;
else if(www.tileIndex[texPos]==ARGB(255,0,0,255))
mapY++;

[Edited by - suliman on September 18, 2006 1:43:53 AM]
anyone? i dont see why this is only working for half my world... Which kinda suggests it doesnt really work at all.

E
Quote:Original post by suliman
float x,y;
hge->Input_GetMousePos(&x,&y);
mouseX=x;
mouseY=y;
mapPixelX=x-panX;
mapPixelY=y-panY;
mapX = (mapPixelX / TILEX) - (mapPixelY / TILEY);
mapY = (mapPixelX / TILEX) + (mapPixelY / TILEY);

int texW = hge->Texture_GetWidth(www.tileTex);
int texPos;

int screenX = (mapY * 0.5 * TILEX) + (mapX * 0.5 * TILEX);
int screenY = (mapY * 0.5 * TILEY) - (mapX * 0.5 * TILEY);

texPos=(texW*(abs(mapPixelY-screenY)))+abs(mapPixelX-screenX);

if(www.tileIndex[texPos]==ARGB(255,0,0,0))
mapY--;
else if(www.tileIndex[texPos]==ARGB(255,255,0,0))
mapX++;
else if(www.tileIndex[texPos]==ARGB(255,0,255,0))
mapX--;
else if(www.tileIndex[texPos]==ARGB(255,0,0,255))
mapY++;


Hmm, I'm not sure I understand what this code is meant to be doing. Are you using the mousemap method? And what are "TILEX" and "TILEY"? Are they the tile width and height?

Anyway, just to clarify: if you are doing a vanilla isometric engine, you don't need to use the mousemap. You can just use the formulae given above, in the second post. Ie, the first section of your code:

float x,y;
hge->Input_GetMousePos(&x,&y);
mouseX=x;
mouseY=y;
mapPixelX=x-panX;
mapPixelY=y-panY;
mapX = (mapPixelX / TILEX) - (mapPixelY / TILEY);
mapY = (mapPixelX / TILEX) + (mapPixelY / TILEY);

And there are the tile-map coordinates: (mapX, mapY) [Assuming you have the panX, panY values working correctly, ie. storing the number of pixels the origin of the screen is from the origin of the tilemap.]
if vanilla is diamond then its vanilla. TILEX and TILEY are w and h (constants)

?
if i use only the lines you suggests and no mousemap(where i pick colors from a texture to offset diagonals). It works, but it only finds every second tile in both dimensions making it quite useless (and still only on the lower half of the world). With the texture map as described above, it works pixel-perfect on the lower half, but is not accurate at all on the upper part with is kinda strange.

edit: I fixed my offset (offset so upper part is considered lower part for colculation, then offset back to reflect the correct tile). Now all map works perfectly, but i never understood why i had to do this. And i still use texture offset, i dont see how this could be done without some kind of diagonal offset. With the fewer-lines sollution, you can only select tiles in a "rectangular" pattern, which kinda takes away the isometric of it all.
Anyway, now my code works!

Thanks for your help
E

[Edited by - suliman on September 19, 2006 3:10:14 AM]

This topic is closed to new replies.

Advertisement