Ok, I’m working on my own time to create a game, and exploring technical possibilities on this adventure !
In the beginning I was planning to do the map 2D plain, the coordinates 10,10 would be easy to calculate, was just a matter of multiply the x,y by the width and height of the small tile that would be in the screen.

But nothing is simple ! My daughters are helping me on the discussions of the game, and also helped to create the map, thanks girls you are the best daughters !! The 8 years old one come with the great idea ! Hey dad, why don’t you make the game like the age of empires or warcraft III maps ? a little bit shifted back … Oh well that began all of this
Now I have a new map to work with

And the nice problem of how to convert from a screen coordinate to the map coordinates ? remember that in this case the screen 0,0 is the top left point of the window.
I will try to describe how I get to the solution that I made, I believe that is not the most I-know-geometry-a-lot but it works and I can explain hehehe
step 1 – divide and conquer
I tough: well, as I believe that there is no way to calculate in one line, let’s see if I can discover how close to a tile of the map the mouse is. To do it I split the map in smaller segments, with half of the width of the tile, and half of the height, getting something like this

So part of the problem was solved (dreamer) divide the screen coordinates by the half of the tile measures and I have what segment the mouse clicked on ! lets say that the tile have 100X50, width of 100 and height of 50, doing so we have segments of 50,25, lets see and example :

we need to find in which segment the mouse is, so :
segment(x) = (int) mouse(x) / segment.width
segment(y) = (int) mouse(y) / segment.height
very simple isn’t it ?
180 / 50 = 3.6 => 3
22 / 25 = 0.88 => 0
then the segment is the 3,0, but this is just the first step
step 2 – triangles are your friends
Now that I have the segment I had to find out if the point is above or under the line that splits the segment in two …. before we go in the formulas we need to remember that the original point 180,22 now have to be converted to something relative to the top left corner of the segment, so the relative.to.segment(x) would be x – ( segment(x) * segmen.width ) that is 30, and relative.to.segment(y) would be y – ( segment(y) * segment.height ) that is 22
relative.to.segment(x) = screen(x) – ( segment(x) * segment.width ) relative.to.segment(y) = screen(y) – ( segment(y) * segment.height )
based on the fact that the tangent of the angle of this line is calculated by the formula :
tangent = oposite side / adjacent side
I just need to store the tangent for the segment, that is segment.height / segment.width, and use it to calculate the y for a given x that would be at the line
let’s see a drawing, that talks more than 1024 words.

so for a given X I calculate the maximum size of Y to be above the line, so if Y is bigger than this value the point is under.
Ye ye we have another problem, sometimes the line is from top-right to bottom-left what make the calculation a little different, in that cases we don’t use the relative.to.segment(x) as adjacent, we need to subtract from the width of the segment the relative.to.segment(x) and then we have the adjacent …

As we already know, nothing is simple, so we need to figure out when the segment have the line for one side and when have to other side … when the sum of the segment(x) and segment(y) is even the the line goes up, when is odd goes down … believe me its true.
step 3 – it’s a kind a magic
this step I don’t know how to explain, I just know that after some observations of the numbers I found out a relation between it, that can be described as follow :
we have a segment that we know which tile it refers to, is the tile(0,0) top-left segment, let’s call it start-segment.
Based on that one all the others will have the information of how much shift is need from the start segment to find the expected segment, look at the image bellow

so based on that information of the shifts from the start segment, we have the following formulas :
shift(x) = tile(x) – tile(y)
shift(y) = tile(x) + tile(y)
that I used to create the following formulas that I used to find the tile(x) and tile(y) based on the shift(x) and shift(y)
tile(y) = ( shift(y) – shift(x) ) / 2
tile(x) = shift(x) + ( shift(y) – shift(x) ) / 2
As I said, these formulas came from lots of tests and thinking about the shifts, tiles, segments … And I really like it because even with lots of small step, I can understand how it works
step 4 – packing everything
And to finish based on the current segment we need to identify if its a NorthWest, NorthEast, SouthWest or SouthEast segment, because for each one we have different rules as we can see in the image bellow

Using the formula
tile(y) = ( shift(y) – shift(x) ) / 2
tile(x) = shift(x) + ( shift(y) – shift(x) ) / 2
We can find the tile(x) and tile(y), but using the following rules :
NorthWest = the values are round
NorthEast = tile(y) has -0.5
SouthWest = tile(y) has +0.5
I believe that this piece is better understood with the source code, isomapjava.txt
Note that is implemented to be used with the framework pulpcore
What you created isn’t an isometric view – with computers the angle is different from the actual isometric angle. You have to go two pixels across, one pixel up every time to create an isometric line.
hehehe Its true Lis, is almost isometric, but what made me happy on that is the fact that I figure it out how to map the screen to the points =)
but thx for pointing me that
[...] my isometric efforts, I will follow my friend advice, and make plain 2D, lets see If I can make it [...]
I think you are doing a lot of extra calculations! You can usde much more maths.
It took me all day, but I get the same results now:
public void getTileAt(int screenX, int screenY){
//adjustment will be 4*tileWidth in your example.
double x = screenX – tileWidth;
//Y*2 -> squares instead of diamonds => 90° = PI/2
//easyer calculations!
double y = screenY*2;
//distance from origin to point in ISO
double r = Math.sqrt((x*x) + (y*y));
double theta = Math.atan2(x, y);
double angle = (Math.PI/4) – theta;
//length of the side of one tile (128/64 are mine)
double rr = Math.sqrt(2*64*64);
//’real x’ is the projection of screen distance by the angles cos
double rx = Math.floor(r* Math.cos(angle) / rr);
//’real x’ is the projection of screen distance by the angles sin
double ry = Math.floor(r* Math.sin(angle) / rr);
System.out.printf(“(%.0f,%.0f)\n”,rx,ry);
}
great job yepke !
Great help for a tricky problem! Thanks! And also thanks for the comments that helped aswell!!
I’ve been working on an isometric engine for the last couple months. I found what seems to be the best method for screen-to-map conversions. I know it works with diamond-type isometric maps, not sure about other types (like staggered and slide).
It’s a simple algebraic equation, rather than having to mess with sqrts and angles, as I know they’re not the most efficient calculations cpu-wise.
Point tileID;
tileID.X = ((tileWidth * mouse.Y) + (tileHeight * mouse.X)) /
(tileWidth* tileHeight);
tileID.Y = ((tileWidth * mouse.Y) – (tileHeight * mouse.X)) /
(tileWidth* tileHeight);