Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » how to convert pixel coords to tile coords for isometric slopes?

This thread is locked; no one can reply to it. rss feed Print
how to convert pixel coords to tile coords for isometric slopes?
Pho75_
Member #12,377
November 2010

If you have standard isometric tiles 64x32 pixels (or diamond 64x64 pixels)
with straight slopes:

How do you convert the x,y pixel coordinates to tile coordinates (0.0-1.0)
for the slopes for all 8 directions?
Assuming they all have the same elevation.

For flat tiles I know the equations are:
map.x = screen.x / TILE_WIDTH + screen.y / TILE_HEIGHT;
map.y = screen.y / TILE_HEIGHT - screen.x / TILE_WIDTH;

What about the slopes?

Can anyone help?

Cheers.

Elias
Member #358
May 2000

I would first do the other direction, go from tile to pixel coordinates. Without loss of generality, I chose the direction sloping towards the upper right edge and made it be as high as the tile:

0.............TILE_WIDTH
.      /`-_
.     /    `-_
.    /       /|
.   /   _   / |
.  / _-´ `-/  |
. /-´     / `-| 
.  `-_   / _-´
.     `-/-´
TILE_HEIGHT * 2

So clearly:

screen.x = map.x * TILE_WIDTH / 2 - map.y * TILE_WIDTH / 2
screen.y = map.x * TILE_HEIGHT / 2 + map.y * TILE_HEIGHT / 2 - TILE_HEIGHT * (1 - map.y)

Now just solve for map.x and map.y:

1) screen.x * 2 / TILE_WIDTH = map.x - map.y
2) screen.y * 2 / TILE_HEIGHT = map.x + map.y - (2 - 2 * map.y) = map.x + 3 * map.y - 2
1-2) screen.x * 2 / TILE_WIDTH - screen.y * 2 / TILE_HEIGHT = - 4 * map.y + 2
Therefore:
map.y = screen.y / TILE_HEIGHT / 2 - screen.x / TILE_WIDTH / 2 + 0.5
map.x = screen.x * 1.5 / TILE_WIDTH + screen.y / TILE_HEIGHT / 2 + 0.5
(I probably did that wrong, it's late...)

The same works for the other 3 directions and for arbitrary slopes.

The 4 additional "diagonal" directions depend on how exactly you have them, but probably you split your tile into two triangles where one triangle is just flat and the other slopes towards one corner.

--
"Either help out or stop whining" - Evert

Ariesnl
Member #2,902
November 2002
avatar

I saw a game once where the mouse controlled a tile shaped curser that would always snap to a tile. The cursor would just move according to the mouse mickeys (Dx,Dy).This made selecting something very easy to implement. I thought "Battle Isle" had such a system.

Perhaps one day we will find that the human factor is more complicated than space and time (Jean luc Picard)
Current project: [Star Trek Project ] Join if you want ;-)

Elias
Member #358
May 2000

Ariesnl said:

I saw a game once where the mouse controlled a tile shaped curser that would always snap to a tile. The cursor would just move according to the mouse mickeys (Dx,Dy).This made selecting something very easy to implement. I thought "Battle Isle" had such a system.

Depends on the game. Most often for something like selecting units with the mouse you don't really want the tile but the unit itself. E.g. if the head sticks out on top of the tile above and you click that head - it still should select the unit and not the tile.

--
"Either help out or stop whining" - Evert

Pho75_
Member #12,377
November 2010

I think I get where you're going.
I haven't been able to solve this simultaneous equation though.
But thanks for the help, Elias.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

I think you're making it more complicated than it needs to be. If you do it a certain way, all you need to do is apply a scale to each dimension and apply some inequalities. This figure shows the map coordinates in tile units.

You can see that the tile units are just a grid of x,y values, with x increasing to the right and y increasing downwards with 0,0 in the upper left corner. This is the same coordinate system Allegro uses.

{"name":"610536","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/b\/bb3158e45a4dabe61c646d94a35ba7f9.png","w":600,"h":545,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/b\/b\/bb3158e45a4dabe61c646d94a35ba7f9"}610536

To convert from tile units to map units all you need to do is apply the scale, which is the width and height of the tiles over 2.

int mapx = (tilex * TILE_WIDTH)/2;
int mapy = (tiley * TILE_HEIGHT)/2;

To convert from map coordinates into whole tile coordinates, you can apply a series of transformations and inequalities. Basically, you test whether or not the point falls on a certain side of a specific line in tile space.

{"name":"610537","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/8\/9818c2559c390dc7dc591b7909196523.png","w":1024,"h":689,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/9\/8\/9818c2559c390dc7dc591b7909196523"}610537

In the figure above, there are 4 lines to test against, numbered one through four, with the corresponding condition indicated by a or b depending on which side of the line it falls. To find the equations of the lines, use the point slope intercept formula :

y = ((y2 - y1)(x2 - x1))*x + b;

This gives us 4 lines

/// Line 1 [Y = -X + 1]
/// Line 2 [Y = X - 1]
/// Line 3 [Y = X + 1]
/// Line 4 [Y = X + 3]

First, find the grid sector where the point falls. I'll call this tile quadrant x and y. Simply apply the inverse scale from above to go from map coordinates to tile space.

float TileQuadrantX = ((float)mapx)/(TILE_WIDTH/2.0f));
float TileQuadrantY = ((float)mapy)/(TILE_HEIGHT/2.0f));

Next we want the base tile x and y to the nearest multiple of 2. Integer division works perfect for this. The reason is that we will be testing against a 2x2 space in the next step.

int BaseTileX = ((int)TileQuadrantX)/2)*2;
int BaseTileY = ((int)TileQuadrantY)/2)*2;

To test against our line pattern we need the tile quadrant position modulus 2.0 to find the position relative to our 2x2 space.

float QuadrantX = fmod(TileQuadrantX , 2.0f);
float QuadrantY = fmod(TileQuadrantY , 2.0f);

Next we test against the lines that divide our 2x2 space. This will give us the correct tile offset for our base tile position.

#SelectExpand
1const float QX = QuadrantX; 2const float QY = QuadrantY; 3/// Line 1 [QY = -QX + 1] 4if (QY >= (-QX + 1)) {/// line condition 1b 5 BaseTileX += 1; 6 BaseTileY += 1; 7 /// Test against line 4 [QY = -QX + 3] 8 if (QY >= (-QX + 3.0)) {/// line condition 4b 9 BaseTileX += 1; 10 BaseTileY += 1; 11 } 12 else {/// line condition 4a 13 /// Test against line 2 [QY = QX - 1] and line 3 [QY = QX + 1] 14 if (QY < (QX - 1)) {/// line condition 2a 15 BaseTileX += 1; 16 BaseTileY -= 1; 17 } 18 else if (QY >= (QX + 1.0f)) {/// line condition 3b 19 BaseTileX -= 1; 20 BaseTileY += 1; 21 } 22 else { 23 /// We are in the center, already taken care of by case 1b 24 } 25 } 26}

Now we have our tile coordinates from our map coordinates. I suggest making two functions to convert from map to tile and tile to map coordinates.

However, despite all this, I may have misunderstood the question. If you're asking for fractional tile coordinates I'm not sure I know how to do that. I think it's just a series of transformations though.

EDIT
I think I see what you're asking. To answer your questions, to get the 8 slopes, just use map coordinates for each tile. So to get from one tile to another, make a line from the two points in map coordinates. It will still travel the same direction.

Pho75_
Member #12,377
November 2010

Thanks Edgar for the detailed reply.
Elias solution proved to be correct, (although his math wasn't ;D). It even works for slopes with arbitrary elevation.
I was finally able to resolve the simultaneous equations for the N,S,E,W slopes.
I just need to do the 4 corners now.

Thanks.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Just a question, why do you need fractional tile coordinates? What does that get you? And if you solved it, you should provide the solutions so people asking the same question in the future get to see the answer and don't have to ask it again.

Pho75_
Member #12,377
November 2010

It gets you sub-tile accuracy.
So you can get the exact coordinates under the mouse cursor.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Pho75_
Member #12,377
November 2010

If I wanted my characters to only stand on the center of a tile, you'd be right.
I'd only need tile coordinates. But I don't want tile-locked movement, so I need sub-tile accuracy.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

You're totally missing what I'm getting at. What I'm saying is why can't you simply track your game object's coordinates in map coordinates (pixels?). You can convert map coords to whole number tile coords any time you need to. And you can more easily track offsets in pixels than you can in floating point tile coordinates (which you have to convert back to map coordinates (pixels) to draw them anyway).

Pho75_
Member #12,377
November 2010

I do track my objects in map coordinates. I need to click on the screen to tell my character where to go.
if you have 3D there is no way to guarantee that 2 pixels next to each other on screen are indeed next to each other in actual coordinates.
If you're looking at a picture on screen, how can you tell if the pixel you're pointing at is close or off in the horizon. you can't unless you can convert x,y screen coords into world coordinates.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

This is the first time you mentioned 3D. I don't think you would need fractional tile coordinates if it was just a standard 2D isometric map though. I won't bug you any more about it.

Please do post the solution though, for future reference for other's sake.

Neil Roy
Member #2,229
April 2002
avatar

I use a mouse map for the various tile types. The white areas in this map are the tile, the coloured areas are the different sides off of it. When you click on a tile, you check where you clicked against the matching tile map to see where you clicked, or if you clicked on a neighbouring tile etc. Simple to implement (at least I think this is what you are talking about).

{"name":"610546","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/3\/a3043314ff5c121b96d07e5ad63cae05.png","w":640,"h":128,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/a\/3\/a3043314ff5c121b96d07e5ad63cae05"}610546

And I agree with Edgar, please share any solutions you came up with as this is a subject I would like to know how others solve these problems as well.

---
“I love you too.” - last words of Wanda Roy

Pho75_
Member #12,377
November 2010

I only used a 2 color mouse map: do determine if I'm over the tile or not.
since I use a heightmap it's possible to have tiles behind each other.
So I can't predict all the intersection types.

I'll post the solution when i get it working. It's still broken since I only get to work on it in my spare time, and my math skills aren't that great.

Neil Roy
Member #2,229
April 2002
avatar

Is this 2D or 3D?! For 2D, the mouse map works. You're very confusing as to what you are working on.

---
“I love you too.” - last words of Wanda Roy

Pho75_
Member #12,377
November 2010

It's isometric 2.5D with heightmap support.
I did say that I'm also using a mousemap. I'm just not familiar with your multi-color technique.
My mouse-map only has 2 colors, for on or off.

Neil Roy
Member #2,229
April 2002
avatar

Here's an excellent article that explains the mouse maps, and it has a terrain with varying heights etc... check this out.

http://archive.gamedev.net/archive/reference/programming/features/mm4ihm/index.html

---
“I love you too.” - last words of Wanda Roy

Go to: