# Adapting tilemap algorithm to support isometric tilemap

I'm using Phaser to build an isometric game. The framework doesn't have support for isometric tilemaps yet, so I'm starting to write a PR for it to support.

What I currently have, loading an isometric tilemap on the current Phaser.Tilemap object, is this:

As you can see, the tiles are wrongly positioned because of the simple 2D tile positioning approach the framework currently uses.

The class that actually makes the parsing of the JSON map and converts it into a tilemap is Phaser.TilemapParser, specifically at line 185.

What I need is some help on where to start adapting this parser – or any other part of the code – in order for it to support isometric tilemaps.

I don't know exactly where to start extending this parser – or even writing a new parser just for isometric tilemaps. Also, I know the calculations are different for positioning isometric tiles, and I want to know too where that change should go here, as I didn't find that either.

• Can you clarify your question a bit? I'm not sure if you're looking for help with an isometric tile-rendering algorithm or if you're just looking for help extending the TilemapParser object. – Cypher Apr 22 '14 at 19:27
• I edited, but the question is actually on where to start adapting this: weather I extend the parser, write a new one, etc. – Daniel Ribeiro Apr 22 '14 at 19:37

You don't need to change the parser, just the renderer.
The tiles will be at the 'same' place, except the projection is different.
The good news is that the good context 2d can do isometric just by setting the right isometric transform.
Once you set it, just draw in a regular way (including drawImage), and all will be drawn in the isometric way !!! magic !!!

So what i suggest you do with phaser to draw the tiles :
-save context.
-set transform to an isometric one.
-draw tiles with regular phaser code.
-restore context.

This image was made just with setTransform + drawImage of random small tile bitmap on a context2D :

How does isometric coordinates work ?
The 'regular' coordinate system is the cartesian coordinates.
It needs a center O, and two unit perpendicular vectors Ux and Uy.
The fact that they are unit vectors means they have a length of 1. It allows such a system not to change distances after translation.
The fact that they are perpendicular allows such a system not to change distances after a rotation.
If you have x and y of a point, you get the points with

P(x,y) = x * Ux + y * Uy.
with Ux = (1,0) and Uy = (0,1).


Now for isometric projection we just release one constraint : Ux and Uy do not have to be perpendicular. So distances will change after a rotation.
But since they are still unit vectors, distances are kept after a translation ( iso - metric == same - distances ).
Since Ux and Uy, are unit vectors, we can write them as

 Ux = (cos A1, sin A1)
Uy = (cos A2, sin A2).


A1 and A2 will be the relative angle between Ux / Uy and the horizontal line :

By changing A1 and A2, you change the axes directions, and you can give the look that you want to your projection.
Obviously, if A1 == A2, both axes are the same and you'll see nothing.
A1 = PI / 6 and A2 = 9 * PI / 10 seems (subjectively) a good starting point for the angles.

to compute where is a (x, y) point, the formula is the same as cartesian : P = xUx + yUy.

To convert from cartesian to isometric, the transform matrix is :

  (in regular mathematical notation)
M =  [ cosA1 sinA1 translateX
cosA2 sinA2 translateY
0     0        1       ] ;

or (in webgl column-by-column notation )
Mgl = [ [ cosA1       cosA2     0 ]
[ sinA1       sinA2     0 ]
[ translateX translateY 1 ]  ]


below i also compute the reverse of the transform matrix to be able to get world coordinates from mouse coordinates.

Notice that i introduced a scale, and also that i allow to change the x aspect ratio if you want to have non-square tiles.

if you want to play with the fiddle it's here (move by pressing mouse).

(version corresponding to the code below) http://jsfiddle.net/gamealchemist/zF2w8/4/

//  Parameters
//

// center of the display on screen
var displayCenterX = 1*canvas.width / 3;
var displayCenterY = 2 * canvas.height / 3;

// angle of the x axis. Should be in [0, PI/2]
var angleX = Math.PI / 6;
// angle of the y axis. Should be in [PI/2, PI[
var angleY = 2.8;

// scale for the tiles
var scale = 120.0;
// relative scale for the x of the tile. use it to stretch tiles.
var relScaleX = 1;

// ----------------------------------------
//     Transforms
// ----------------------------------------
var transfMatrix = [Math.cos(angleX), Math.sin(angleX),
Math.cos(angleY), Math.sin(angleY)];
var _norm = relScaleX + 1;
relScaleX /= _norm;
transfMatrix[0] *= scale * relScaleX;
transfMatrix[1] *= scale  * relScaleX;
transfMatrix[2] *= scale / _norm;
transfMatrix[3] *= scale / _norm;
// matrix reverse
var determinant = transfMatrix[0] * transfMatrix[3] - transfMatrix[2] * transfMatrix[1];
var transfMatrixRev = [transfMatrix[3], -transfMatrix[1], -transfMatrix[2], transfMatrix[0]];
transfMatrixRev[0] /= determinant;
transfMatrixRev[1] /= determinant;
transfMatrixRev[2] /= determinant;
transfMatrixRev[3] /= determinant;

// use with :
c.setTransform(transfMatrix[0],transfMatrix[1],
transfMatrix[2],transfMatrix[3],
displayCenterX, displayCenterY);


.

 // regular 3x3 transform matrix in webGL format :
var mat3 = [ transfMatrix[0],transfMatrix[2], 0,
transfMatrix[1],transfMatrix[3], 0,
displayCenterX, displayCenterY, 1
] ;


( for the fun, the pseudo-3D version : http://jsfiddle.net/gamealchemist/zF2w8/5/ )

• Thanks for your answer, but I'm afraid I would need a more simpler explanation. Can you explain what the transformation part does? – Daniel Ribeiro Apr 22 '14 at 22:37
• @DanielRibeiro : i explained more the transform. – GameAlchemist Apr 23 '14 at 7:52