Isometric Tile Plotting
Hello,
I am new to this forum (which is great by the way) and I am working on a game with an isometric viewpoint. I have worked out (Google is my friend) how to draw and click tiles in a staggered viewpoint  see image below:
The (simplified) routine I use to calculate the x,y coordinates for where to draw the tiles is (note, this is REALbasic code):
However, I want to know how to draw a rotated isometric viewpoint like so:
Any suggestions? I have tried for hours to work out where to draw the tiles to. I want to start drawing from (0,0) and I have been trying to figure the coordinates that the tiles should be put as we go from (0,0) to (0,1) to (0, 2), etc but I can't work out the algorithm. It would seem I need to do the following (assuming 64x32 tiles):
(0,0) = (0,0)
(0,1) = (32, 16)
(0,2) = (64, 32)
etc, and
(1,0) = (32, 16)
(2,0) = (64, 32)
Where negative x coordinates represent points to the left of the mid point of the xaxis (where the map is draw from).
Any help would be greatly appreciated.
I am new to this forum (which is great by the way) and I am working on a game with an isometric viewpoint. I have worked out (Google is my friend) how to draw and click tiles in a staggered viewpoint  see image below:
The (simplified) routine I use to calculate the x,y coordinates for where to draw the tiles is (note, this is REALbasic code):
Code:
for y = 0 to (rows  1)
for x = 0 to (columns  1)
' Calculate MapX
MapX = x * TileWidth
if isOdd(y) then ' shift MapX to the right
MapX = MapX + (TileWidth/2)
end if
' Calculate MapY
MapY = y * (TileHeight/2)
' Add this tile to the array
MapArray(x, y) = theTile
next x
next y
Any suggestions? I have tried for hours to work out where to draw the tiles to. I want to start drawing from (0,0) and I have been trying to figure the coordinates that the tiles should be put as we go from (0,0) to (0,1) to (0, 2), etc but I can't work out the algorithm. It would seem I need to do the following (assuming 64x32 tiles):
(0,0) = (0,0)
(0,1) = (32, 16)
(0,2) = (64, 32)
etc, and
(1,0) = (32, 16)
(2,0) = (64, 32)
Where negative x coordinates represent points to the left of the mid point of the xaxis (where the map is draw from).
Any help would be greatly appreciated.
This comes out of the Isometric Game Programming with DirectX 7 book. Its C++, I dont know BASIC:
PlotX and PlotY are the coords for placing the tile apparently. I dont know if the starting (0,0) drawing coords are in the middle or not.
PlotX and PlotY are the coords for placing the tile apparently. I dont know if the starting (0,0) drawing coords are in the middle or not.
Code:
for( x=0; x<ROWS; x++ ) {
for( y=0; y<COLUMNS; y++ ) {
plotX = (xy)*TileWidth/2;
plotY = (xy)*TileHeight/2;
}
}
Its like when people say someone is programming by smashing things around with a huge hammer, you need to just get a bit of paper and work it out calmly.
In standard computer coordinates, not the inverted, confusing and wrongly chosen quartz coordinates.
As the x coordinate increases the tiles move diagonally downwards and to the right,
so
x_tile = x*64
y_tile = x*32
when the y coordinate increases the tiles move diagonally downwards and to the left
so
x_tile = y*64
y_tile = y*32
you add them together to get
x_tile = (xy)*64
y_tile = (y+x)*32
that will give you the tile (0, 0) at (0, 0) and the tile (1, 1) at (0, 64)
You will probably want your final equation to be
x_tile = screen_width/232+(xy)*64
y_tile = screen_height(y+x)*32
did you think about tile (0, 0) and tile (1, 1) being drawn in the same place. I hope thats a typo and not an error in the book :o
In standard computer coordinates, not the inverted, confusing and wrongly chosen quartz coordinates.
As the x coordinate increases the tiles move diagonally downwards and to the right,
so
x_tile = x*64
y_tile = x*32
when the y coordinate increases the tiles move diagonally downwards and to the left
so
x_tile = y*64
y_tile = y*32
you add them together to get
x_tile = (xy)*64
y_tile = (y+x)*32
that will give you the tile (0, 0) at (0, 0) and the tile (1, 1) at (0, 64)
You will probably want your final equation to be
x_tile = screen_width/232+(xy)*64
y_tile = screen_height(y+x)*32
cheatdeath Wrote:plotX = (xy)*TileWidth/2;
plotY = (xy)*TileHeight/2;
did you think about tile (0, 0) and tile (1, 1) being drawn in the same place. I hope thats a typo and not an error in the book :o
Sir, e^iÏ€ + 1 = 0, hence God exists; reply!
Thanks unknown for your reply,
Unfortunately, it doesn't seem to be correct
The formulae (ignoring the screen width/height offsets):
x_tile = (xy)*64
y_tile = (y+x)*32
gives the following output:
Tile > Coords > Should be
(0, 0) > (0, 0) > (0, 0)
(0, 1) > (64, 32) > (32, 16)
(0, 2) > (128, 64) > (64, 32)
(1, 0) > (64, 32) > (32, 16)
(2, 0) > (128, 64) > (64, 32)
Frustrating isn't it?
@CheatDeath:
That code can't work  Unknown was right, most of the tiles get drawn in the same place!
Garry,
Unfortunately, it doesn't seem to be correct
The formulae (ignoring the screen width/height offsets):
x_tile = (xy)*64
y_tile = (y+x)*32
gives the following output:
Tile > Coords > Should be
(0, 0) > (0, 0) > (0, 0)
(0, 1) > (64, 32) > (32, 16)
(0, 2) > (128, 64) > (64, 32)
(1, 0) > (64, 32) > (32, 16)
(2, 0) > (128, 64) > (64, 32)
Frustrating isn't it?
@CheatDeath:
That code can't work  Unknown was right, most of the tiles get drawn in the same place!
Garry,
use tile_width and tile_height /2.
*smacks self on head*
*smacks self on head*
Sir, e^iÏ€ + 1 = 0, hence God exists; reply!
Thanks unknown!
Now I need to get to work on tile selection with this new viewpoint.
Thanks again!
Garry
Now I need to get to work on tile selection with this new viewpoint.
Thanks again!
Garry
Okay, please don't think that i'm not doing any work but....
I am now struggling with tile selection in this rotated viewpoint.
With the staggered viewpoint (see my first picture) I am able to work out where a person has clicked by using a "MouseMap"  see image below:
I divide the screen up into "regions"  each region is 64x32 pixels (i.e. tileWidth x tileHeight). I work out which region the mouse is in using the following code (you can ignore scrollOffset  it's only relevant if the map has been scrolled):
Once I know what region the mouse cursor is  I calculate it's coordinates (mouseMapX, mouseMapY) within the region (for instance, if it's in the top left most corner the coordinates would be 0,0) using this code:
Once I know these coordinates, I calculate which region (white, red, green, blue or yellow) the cursor is in on the mouseMap. For each coloured region there is a set regionOffset (e.g. for red I decrease regionX by 1 and regionY by 1). At this point I can calculate the tile we are hovering over using the code:
I know this sounds convoluted but I was really struggling a way to work out which tile the mouse was hovering over using maths !
Needless to say, I think this approach is probably rubbish and I would appreciate any advice on a better approach. Not only this, but I cannot work out how to make this approach work with a rotated view (as you can't simply slice the map into a grid because the tiles are arranged in a diamond format now and not in straight lines!).
I hope this makes some sense  I have just spent ages doing the following maths with the hope that I could calculate the tile I was over (these calculations are derived from unknown's method of plotting said tiles):
x_tile = screen_width/232+(xy)*(tileWidth/2)
y_tile = screen_height(y+x)*(tileHeight/2)
simplified is (for a 64x32 tile, ignoring the offsets):
x_tile = (xy)*32
y_tile = (y+x)*16
thus,
x_tile/32 = xy
x= x_tile/32 + y
y_tile/16 = x+y
y_tile/16 = x_tile/32 + 2y
2y = y_tile/16  x_tile/32
y = y_tile/32  x_tile/64
y = 2y_tile  x_tile/64
x = x_tile/32 + 2y_tile  x_tile/64
x = x_tile/64 + y_tile/32
I have tried these equations (I know x_tile and y_tile as these are the mouse coordinates, right?).
I am so confused!
Thanks in advance,
Garry
I am now struggling with tile selection in this rotated viewpoint.
With the staggered viewpoint (see my first picture) I am able to work out where a person has clicked by using a "MouseMap"  see image below:
I divide the screen up into "regions"  each region is 64x32 pixels (i.e. tileWidth x tileHeight). I work out which region the mouse is in using the following code (you can ignore scrollOffset  it's only relevant if the map has been scrolled):
Code:
regionX = (mouseX  xScrollOffset)\tileWidth
regionY = ((mouseY  yScrollOffset)\tileHeight) * 2
Once I know what region the mouse cursor is  I calculate it's coordinates (mouseMapX, mouseMapY) within the region (for instance, if it's in the top left most corner the coordinates would be 0,0) using this code:
Code:
MouseMapX = (mouseX  xScrollOffset) mod tileWidth
MouseMapY = (mouseY  yScrollOffset) mod tileHeight
Once I know these coordinates, I calculate which region (white, red, green, blue or yellow) the cursor is in on the mouseMap. For each coloured region there is a set regionOffset (e.g. for red I decrease regionX by 1 and regionY by 1). At this point I can calculate the tile we are hovering over using the code:
Code:
tileX = regionX + regionDX
tileY = regionY + regionDY
I know this sounds convoluted but I was really struggling a way to work out which tile the mouse was hovering over using maths !
Needless to say, I think this approach is probably rubbish and I would appreciate any advice on a better approach. Not only this, but I cannot work out how to make this approach work with a rotated view (as you can't simply slice the map into a grid because the tiles are arranged in a diamond format now and not in straight lines!).
I hope this makes some sense  I have just spent ages doing the following maths with the hope that I could calculate the tile I was over (these calculations are derived from unknown's method of plotting said tiles):
x_tile = screen_width/232+(xy)*(tileWidth/2)
y_tile = screen_height(y+x)*(tileHeight/2)
simplified is (for a 64x32 tile, ignoring the offsets):
x_tile = (xy)*32
y_tile = (y+x)*16
thus,
x_tile/32 = xy
x= x_tile/32 + y
y_tile/16 = x+y
y_tile/16 = x_tile/32 + 2y
2y = y_tile/16  x_tile/32
y = y_tile/32  x_tile/64
y = 2y_tile  x_tile/64
x = x_tile/32 + 2y_tile  x_tile/64
x = x_tile/64 + y_tile/32
I have tried these equations (I know x_tile and y_tile as these are the mouse coordinates, right?).
I am so confused!
Thanks in advance,
Garry
I'm not sure whether this is possible with RealBASIC (I've only used it in OpenGL), but an alternative approach to convoluted maths is to use colourpicking; render a copy of the tiles to an offscreen buffer, where each tile has a colour which can be easily interpreted as a coordinate (i.e. tile 0,0 would be #000000, tile 1,0 #000100, tile 1,1 #000101, outside the tiles would be #ff0000); then, when the user clicks the mouse, simply grab the colour of the pixel at the coordinates of the mouse click and interpret the pixel's colour to arrive at the tile coordinates.
Mark Bishop
What you need is to map your coordinate system. Basically, you need to multiply your (mouseX,mouseY) vector by a matrix that maps your diamond ring to an axis aligned square grid. Judging from the images, your matrix should be applying both rotation and shear.
So, to rotate & shear your (mouseX,mouseY) vector (the mouse position) to map it to your board, simply multiply it by the (fixed and precomputed) "rotation & shear" matrix. To obtain this matrix, you need to calculate each one separately and then multiply them.
Here is a page describing rotation & shear matrices (among others):
http://www.cc.gatech.edu/gvu/multimedia/...ransf.html
A member of iDevGames also has a nice page about this, but I can't seem find the link, sorry.
Anyway, once you finally have your point mapped from screenspace to boardspace, all you need to do is:
That way you can reference your block in a 2D array like this:
Edit: Actually, don't bother with the above, here what it boils down to:
http://www.bookofhook.com/Article/GameDe...opmen.html
Go to the very end of that article, "Screen to Map Transformation", it gives you the exact formulas for the map to screen and screen to map transformations.
So, to rotate & shear your (mouseX,mouseY) vector (the mouse position) to map it to your board, simply multiply it by the (fixed and precomputed) "rotation & shear" matrix. To obtain this matrix, you need to calculate each one separately and then multiply them.
Here is a page describing rotation & shear matrices (among others):
http://www.cc.gatech.edu/gvu/multimedia/...ransf.html
A member of iDevGames also has a nice page about this, but I can't seem find the link, sorry.
Anyway, once you finally have your point mapped from screenspace to boardspace, all you need to do is:
Code:
tileX = mappedMouseX%lengthOfTileSide;
tileY = mappedMouseY%lengthOfTileSide;
That way you can reference your block in a 2D array like this:
Code:
tile[tileX][tileY]
Edit: Actually, don't bother with the above, here what it boils down to:
http://www.bookofhook.com/Article/GameDe...opmen.html
Go to the very end of that article, "Screen to Map Transformation", it gives you the exact formulas for the map to screen and screen to map transformations.
PowerMacX Wrote:A member of iDevGames also has a nice page about this, but I can't seem find the link, sorry.
This? (ThemsAllTook's tutorials)
Mark Bishop
Yes, that's the one! (but see my edit to my previous post)
Thanks for the link.
Bearing in mind that,although I did pure maths at Alevel, 6 years of boozy medical school has left slightly less sharp than I used to be !
Looking at the article at bookofhook, i'm not sure what mx, my, sx, sy are. I'm guessing that mx/my are the column/row of the tile (mapX, mapY) and that sx, sy are the mouseX and mouseY coordinate  right?
I hate it when 'simple' things seem overly complicated!
Garry,
Bearing in mind that,although I did pure maths at Alevel, 6 years of boozy medical school has left slightly less sharp than I used to be !
Looking at the article at bookofhook, i'm not sure what mx, my, sx, sy are. I'm guessing that mx/my are the column/row of the tile (mapX, mapY) and that sx, sy are the mouseX and mouseY coordinate  right?
I hate it when 'simple' things seem overly complicated!
Garry,
Yes, sx,sy are screenX,screenY (or mouseX,mouseY) and mx,my are mapX,mapY.
Some notes: the formula you want is the last one, but it can be simplified even further, to this:
That is, the formula in the page for mX actually says:
mX = (64*sY + 32*sX)/(64*32)
but that can be rewritten to just:
mx = sY/32 + sX/64
as in the code above (the same applies for mY)
Also, this assumes that screenY increases when you move your mouse down, and that when the mouse is at (0, 0) you are in the tile (0, 0). Of course, since the tile won't be at (0, 0) on the screen, remember to translate (subtract) its real coordinates before using screenX/screenY. That is, if the top corner of your (0, 0) tile is at (100, 100) on the screen, you should subtract 100 from screenX and from screenY before applying the formula.
Finaly, mX and mY should be integers, you should truncate the result of the formulas if your language doesn't do it automatically and, you have to check for bounds (values < 0 are outside your map, and > num. horizontal/vertical tiles are also outside). Here are some screen vs. map results so you can figure out what it is doing:
As you can see, if you truncate the mapX & mapY values, you get the correct tile. For instance, lets say that your first tile has its top corner on the screen at x:100,y:200. Then, if your mouse is at (100, 216) it will be exactly in the center of this first tile. In your code:
From the table, screenX,Y with (0, 16) gives you a mapX,Y of (0.5, 0.5) which means the exact middle of tile (0,0). If you then move your mouse 32 pixels down from there (mouseY = 248 > screenY = 48), you'll get mapX: 1.5 mapY: 1.5, meaning you are now in the exact middle of the tile (1,1). Likewise, (32,32) gives you (1.5, 0.5) which is the middle of tile (1,0), and so on.
As I mentioned, truncate your mapX, mapY values to get the tile. The decimal part only tells you where, within a tile, is the mouse positioned, with .0 being a corner and .5 being the exact middle.
Some notes: the formula you want is the last one, but it can be simplified even further, to this:
Code:
mapX = screenY/32 + screenX/64
mapY = screenY/32  screenX/64
That is, the formula in the page for mX actually says:
mX = (64*sY + 32*sX)/(64*32)
but that can be rewritten to just:
mx = sY/32 + sX/64
as in the code above (the same applies for mY)
Also, this assumes that screenY increases when you move your mouse down, and that when the mouse is at (0, 0) you are in the tile (0, 0). Of course, since the tile won't be at (0, 0) on the screen, remember to translate (subtract) its real coordinates before using screenX/screenY. That is, if the top corner of your (0, 0) tile is at (100, 100) on the screen, you should subtract 100 from screenX and from screenY before applying the formula.
Finaly, mX and mY should be integers, you should truncate the result of the formulas if your language doesn't do it automatically and, you have to check for bounds (values < 0 are outside your map, and > num. horizontal/vertical tiles are also outside). Here are some screen vs. map results so you can figure out what it is doing:
Code:
screenX screenY mapX mapY
0 0 0 0
16 0 0.25 0.25 (outside the map!)
32 0 0.5 0.5 (outside the map!)
0 16 0.5 0.5
0 48 1.5 1.5
32 32 1.5 0.5
64 48 2.5 0.5
96 64 3.5 0.5
As you can see, if you truncate the mapX & mapY values, you get the correct tile. For instance, lets say that your first tile has its top corner on the screen at x:100,y:200. Then, if your mouse is at (100, 216) it will be exactly in the center of this first tile. In your code:
Code:
screenX = mouseX  100 'so, screenX = 0
screenY = mouseY  200 'so, screenY = 16
From the table, screenX,Y with (0, 16) gives you a mapX,Y of (0.5, 0.5) which means the exact middle of tile (0,0). If you then move your mouse 32 pixels down from there (mouseY = 248 > screenY = 48), you'll get mapX: 1.5 mapY: 1.5, meaning you are now in the exact middle of the tile (1,1). Likewise, (32,32) gives you (1.5, 0.5) which is the middle of tile (1,0), and so on.
As I mentioned, truncate your mapX, mapY values to get the tile. The decimal part only tells you where, within a tile, is the mouse positioned, with .0 being a corner and .5 being the exact middle.
I'm hoping that someone can help me here. This has been bothering me for a long time.
I can't get this to work correctly. When I'm in the top left of the tile it's correct, but if I'm in the bottom left or bottom right of the first tile it goes to the next tiles.
How is 0.16 in the middle of the middle of the first tile? Wouldn't it be 32,16 since the tiles are 64x32? The reason this doesn't make sense to me I think is why my code is acting as it is.
Here is what I use to draw:
And here is what I use to map mouse to map:
I can't get this to work correctly. When I'm in the top left of the tile it's correct, but if I'm in the bottom left or bottom right of the first tile it goes to the next tiles.
Quote:From the table, screenX,Y with (0, 16) gives you a mapX,Y of (0.5, 0.5) which means the exact middle of tile (0,0).
How is 0.16 in the middle of the middle of the first tile? Wouldn't it be 32,16 since the tiles are 64x32? The reason this doesn't make sense to me I think is why my code is acting as it is.
Here is what I use to draw:
Code:
//draw the map
for(row=0;row<MAP_ROW;row++)
{
for(col=0;col<MAP_COL;col++)
{
drawX = col * (TILE_W/2)  row * (TILE_W/2) + startX;
drawY = col * (TILE_H/2) + row * (TILE_H/2) + startY;
draw_sprite(buffer, map[row][col].image, drawX, drawY);
}
}
And here is what I use to map mouse to map:
Code:
if(mouse_b & 1)
{
screenX = mouse_x  startX;
screenY = mouse_y  startY;
//these are floats I did for testing purposes
testCol = screenY/TILE_W + screenX/TILE_H;
testRow = screenY/TILE_W  screenX/TILE_H;
//after this if I'm in bottom right of the first tile testCol = 1, which it should = 0
//these are ints so they get truncated
mapCol = testCol;
mapRow = testRow;
if(mapCol > 1 && mapCol < MAP_COL && mapRow > 1 && mapRow < MAP_ROW)
map[mapRow][mapCol].image = highlighted;
}
Quote:How is 0,16 in the middle of the middle of the first tile? Wouldn't it be 32,16 since the tiles are 64x32?
(0, 0) would be the top corner of the top tile. The left corner of that 64x32 tile would be at (32, 16), the right corner at (32, 16) hence 64 pixels wide and the bottom corner would be at (0, 32) that is, 32 pixels high. Does that make sense?
Possibly Related Threads...
Thread:  Author  Replies:  Views:  Last Post  
Plotting a line through a grid  cloke  3  2,492 
Aug 22, 2004 08:50 PM Last Post: cloke 

Isometric tile plotting and such  CarbonX  2  2,457 
Aug 13, 2003 04:33 PM Last Post: aaronsullivan 