5
\$\begingroup\$

I'm currently trying to add sprites to an isometric Tiled TMX map using Objects in cocos2d. The problem is the X and Y metadata from TMX object are in standard 2d format (pixels x, pixels y), instead of isometric grid X and Y format. Usually you would just divide them by the tile size, but isometric needs some sort of transform.

For example on a 64x32 isometric tilemap of size 40 tiles by 40 tiles an object at (20,21)'s coordinates come out as (640,584)

So the question really is what formula gets (20,21) from (640,584)?

\$\endgroup\$
1
  • \$\begingroup\$ If possible, I might post the solution, after I recheck the dot product method \$\endgroup\$
    – user1542
    May 22, 2012 at 8:12

3 Answers 3

9
\$\begingroup\$

After a few days of researching, I found a solution to this particular transform. This is much more mathematical than program-oriented. Therefore, I will be using pseudo code.

Now, given a screen coordinate (x,y), we first want to represent (x,y) respected, or fixed, to the world, not the screen. For example, my game use the top-left most corner of isometric map as (0,0). So anything representation of coordinates in this game will be respected to this world.

enter image description here

Therefore, the new coordinate is calculated like this:

inputWorldCoordXY = inputScreenCoordXY - drawOffsetXY

where drawOffset in my program is the screenCoordXY of the top-left most corner of my isometric map.

The reason we do this is because we want an isometric world coordinate system, not isometric screen coordinate system. As of what we have done so far, we have a cartesian world coordinate system, but we want a projected, or isometric, world coordinate system.

To accomplish this, I'd like to start with the theory behind it. In normal cartesian system, any coord point can be represented in form of vector. These vectors have vector's component, which can be represented by what we called basis vector. In 2D cartesian coord, we have two basis vector i and j, representing x and y respectively.

For a better clarification, the following point can be expressed as vector v which can be represent as a sum of cartesian basis vectors 3i+4j:

enter image description here

So, how does this relate to isometric coord system? Well, the concept is the same, in any isometric coordinate system, any point can be represent in form of vector components, where the basis vectors are parallel with isometric axis:

enter image description here

Let the isometric basis vectors be U,V respectively.

Let vectorW be a vector representation of the point of unknown coordinate system. This vector can be represented with either sum of cartesian components or isometric components. These two ways of representing produce the same vector.

vectorW = cartesianPointX*i + cartesianPointY*j = isometricPointX*U + isometricPointY*V

Now, given that we already know where the point lies in cartesian coordinate and representation of vector U and V in term of cartesian i j. What we want to find is the isometric counterpart of this point: isometricPointXY, which is our desired isometric coordinate. Now, with U,V, and W in term of i j, which enable them to dotproduct each other and produce scalar quantity. We can use this property to produce 2 simultaneous equations:

let A.B be A dotproduct B, from equation above

W.U = isometricPointX * (U.U) + isometricPointY * (U.V)
W.V = isometricPointX * (U.V) + isometricPointY * (V.V)

Dotproduct produce scalar value, or constant. Therefore, we have a simultaneous equation, which can be solve using any mathematical method of your choice--- I prefer cramer rule.

Another thing to point out is the magnitude of U and V will expand or compress your isometric coordinate.

For example, if I define u and v to exactly cover 1 full isometric tile, then (1,1) would be the same thing as 1u + 1v which is the bottom-right corner of the first tile in my isometric system, where top-left most is the origin.

\$\endgroup\$
2
  • \$\begingroup\$ If there is any error in my concept, please tell me too, thanks. I hope this help many isometric game maker---- I haven't find a clean resource on this yet on internet... \$\endgroup\$
    – user1542
    May 24, 2012 at 7:37
  • \$\begingroup\$ It will be extremely helpful if we (programmer) got the code example also... :) \$\endgroup\$
    – swdev
    Dec 17, 2013 at 14:54
2
\$\begingroup\$

So I guess what you're saying is that you want to convert from world space (isometric coordinates) to screen space (a point on the screen).

This is a known and solved problem in 3D graphics, so we can use a transformation matrix. First, let me give you the general solution and then we'll work our way up to your specific case.

The general solution is that you have a projection matrix. It can be perspective or orthogonal, it doesn't matter. It transforms points from world space to clip space, which is a really complicated 4D (yes, four) space that will make your head hurt if you think about it too long. This results in a homogenized space coordinate, meaning that it starts at the center of the screen, runs from -1 to 1 on the horizontal plane (-1 being left, 1 being right) and -1 to 1 on the vertical plane (-1 being up, 1 being down).

So our function becomes:

tb::Vec2 ProjectOnScreen(const tb::Vec3& a_WorldPosition)
{
    tb::Vec3 homogenized_pos = m_MatrixProjection * a_WorldPosition;

    return tb::Vec2(
        (homogenized_pos.x * 0.5f + 0.5f) * m_WindowWidth,
        (1.f - (homogenized_pos.y * 0.5f + 0.5f)) * m_WindowHeight
    );
}

As you can see, it uses these crucial variables:

  • a_WorldPosition - As the name implies, this is position in world space, for instance (0.0, 50.0, 0.0)

  • m_MatrixProjection - The projection matrix. This is often the combination of the camera transform (think rotation and position) with the actual projection matrix.

  • m_WindowWidth - The width of the window in pixels.

  • m_WindowHeight - The height of the window in pixels.

So, what about your specific case? You mention that you have an isometric projection. That means an orthographic projection matrix and a camera that is fixed to a certain angle, let's say 45 degrees on the Z axis and 90 degrees on the Y axis.

// note: I have swapped the bottom and top parameters 
// of the glOrtho function for my own convenience

m_MatrixScreen.FromOrthographic(
    0.f, m_WindowWidth, 
    0.f, m_WindowHeight, 
    -1.f, 1.f
);

m_MatrixCamera.Identity();
m_MatrixCamera.AddRotationZ(45.f);
m_MatrixCamera.AddRotationY(90.f);
m_MatrixCamera.AddTranslation(m_Camera->GetPosition());

m_MatrixProjection = m_MatrixScreen * m_MatrixCamera;

If you plug that matrix into the function you should get the results you want.

\$\endgroup\$
1
\$\begingroup\$

Knight666, this helped me TREMENDOUSLY solving this issue.

However, there is some scaling to do as well; this code will not work out of the box. I use:


isoTransform = new Matrix4();
isoTransform.idt();
isoTransform.translate(0.0f, 0.25f, 0.0f);
isoTransform.scale((float)(Math.sqrt(2.0) / 2.0), (float)(Math.sqrt(2.0) / 4.0), 1.0f);
isoTransform.rotate(0.0f, 0.0f, 1.0f, -45.0f);

The reason for these weird sqrt(2) is all explained there: http://www.alcove-games.com/isometric_tile_picking.php

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .