2
\$\begingroup\$

I'm working on 2d Isometric game in ruby and gosu, although my problem is probably universal. My map is saved in 2d array:

@map_tiles[layer][y][x] = tile_id

Each tile is displayed on coordinates:

isoX = (x * @tile_width/2) - (y * @tile_height)
isoY = ((x * @tile_width/2) + (y * @tile_height)) / 2

So it's displayed in "diamond" like way. But I'm having a problem with calculating two things. - Entity's tile_x and tile_y (on which tile is the entity positioned) when given x and y, and; - Entity's x and y when I'm sending it's tile_x and tile_y.

One method is pretty much the other one reversed. I tried various methods I found over internet, but either I'm doing something wrong, or I don't understand the instructions correctly. The closest I got is:

@x = (tile_x * 32) - (tile_y*32)
@y = ((tile_x * 32) + (tile_y * 32) / 2)

for finding @x and @y based on tiles (player "teleportation" method), and

@tile_x = ((@x / 32) + (@y / 32)) / 2
@tile_y = ((@y / 16) - (@x / 32)) / 2

But they kinda don't work correctly.
- When I send player to tile position (4, 3), he is displayed at (5, 4), and after recalculating it's tile_x/y position, printing says it is at tiles (3,5)
- When I send player to tile position (3, 4), he is displayed at (4, 5), and after recalculating it's tile_x/y position, printing says it is at tiles (2,5)
- When I send player to tile position (4, 2), he is displayed at (5, 3), and after recalculating it's tile_x/y position, printing says it is at tiles (2,5)

So you can clearly see that something's not right here.

That's pretty much it, thanks in advance. I can post the code on github if it's neccessary, but I reckon the problem lies in what I posted.

\$\endgroup\$
  • \$\begingroup\$ Would you kindly post a screenshot to get the visual idea of how tiles are rendered? \$\endgroup\$ – Helbreder Nov 17 '13 at 16:36
  • \$\begingroup\$ Sure, there are two screenshots, first one is how it displays tiles immediately: dl.dropboxusercontent.com/u/18909657/… And this is how it looks like when I move the camera to the left (displays whole map) dl.dropboxusercontent.com/u/18909657/… Numbers over tiles are displaying (x,y) of given tile. \$\endgroup\$ – ekharrtoll Nov 17 '13 at 17:40
3
\$\begingroup\$

We need to find a linear transformation between two bases of a linear space: a base for a screen coordinates and a base for game grid coordinates.

Let's define our base vectors for both cases:

Vectors defined Larger version

  • x and y vectors are basis for screen coordinates (define pixel coordinates)
  • a and b vectors are basis for game grid coordinates (define tile coordinates)
  • additional t vector define offset of grid space origin point relative to screen space origin point in screen space coordinates.

We can describe our x, y, a, b and t vectors in screen space coordinates as:

x = [ x0, x1 ] = [  1,   0   ]
y = [ y0, y1 ] = [  0,   1   ]
a = [ a0, a1 ] = [  w/2, h/2 ]
b = [ b0, b1 ] = [ -w/2, h/2 ]
t = [ t0, t1 ]

We can define our screen space base to grid space base transition matrix as:

    | a0 b0 |   | w/2  -w/2 |
P = |       | = |           |
    | a1 b1 |   | h/2   h/2 | 

To get screen space coordinates from grid space coordinates all we need is to multiply transition matrix P by transposed grid space vector, like so:

             |       gx      |
             |               |
             |       gy      |
------------------------------
| w/2  -w/2  | gx*w/2 - gy*w/2
|            |
| h/2   h/2  | gx*h/2 + gy*h/2

Taking into accout the base offset vector, the final screen space coordinates are:

s = [ sx, sy ] = [ (gx-gy) * w/2 + t0,  (gx+gy) * h/2 + t1 ]

To get grid space vector coordinates from screen space vector coordinates we need to find inversed P matrix ...

    | p00 p10 |
P = |         |
    | p01 p11 |  

         1      |  p11  -p10 |
Pinv = ------ * |            |
       det(P)   | -p01   p00 |

det(P) = p00 * p11 - p10 * p01 = w/2 * h/2 + w/2 * h/2 = w * h/2

         2     |  h/2  w/2 |   |  1/w  1/h |
Pinv = ----- * |           | = |           |
        w*h    | -h/2  w/2 |   | -1/w  1/h |

... and multiply it by transposed screen space vector:

             |       sx     |
             |              |
             |       sy     |
-----------------------------
|  1/w   1/h |  sx/w + sy/h |
|            |              |
| -1/w   1/h | -sx/w + sy/h | 

So, the final grid space vector is given as:

g = [ gx, gy ] = [ (sx - t0)/w + (sy - t1)/h, -(sx - t0)/w + (sy - t1)/h ]

There's a short c++ program to test defined transformations (exact parameters are taken from a screenshot in my post):

#include <iostream>
using namespace std;

const float w = 64.0f;
const float h = 32.0f;

const float t0 = 800.0f;
const float t1 = 123.0f;


void gridToScreenSpace( float gx, float gy )
{
    cout << "Grid space [" << gx << ", " << gy << "] in screen space: [";
    cout << ( gx - gy ) * w / 2.0f + t0;
    cout << ", ";
    cout << ( gx + gy ) * h / 2.0 + t1;
    cout << "]" << endl;
}

void screenToGridSpace( float sx, float sy )
{
   cout << "Screen space [" << sx << ", " << sy << "] in grid space: [";
   cout << ( sx - t0 ) / w + ( sy - t1 ) / h;
   cout << ", ";
   cout << -1.0f * ( sx - t0 ) / w + ( sy - t1 ) / h;
   cout << "]" << endl;
}

int main( )
{
    screenToGridSpace( 798, 360 );
    gridToScreenSpace( 7, 7 );

    return 0;
}

... and the results:

Screen space [798, 360] in grid space: [7.375, 7.4375]
Grid space [7, 7] in screen space: [800, 347]
\$\endgroup\$
1
\$\begingroup\$
isoX = (x * width/2) - (y * height)
isoY = ((x * width/2) + (y * height)) / 2

if that's your World coordinates of tile[x,y] then you have to solve system for x,y and you get tile indices like this

x=(2*isoY + isoX) / width 
y=(2*isoY - isoX) / (2*height)

but those are real values so you have to floor them to get indices

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.