## Isometric tile picking

Download the ready to use Eclipse project for this tutorial

This tutorial will teach you how to achieve picking in an isometric 2D game. It assumes you’ve got some basic knowledge about how to draw isometric worlds and basic game programming knowledge.

When I first made an isometric game, a question came to my mind: how to know on which tile the user clicks. This is a fundamental question and you’ll need this for sure in any isometric world. Searching the web didn’t bring any interesting results; some of them were actually really wrong, using very complex math wizardry for what can be achieved by a simple **transform matrix**.

## The problem

A classic isometric game is made of tiles of a length twice the size of the height. For instance, 64×32 tiles are pretty popular. For the rest of this tutorial, we will draw the tiles with a width of 1.0f and a height of 0.5f. It doesn’t really matter; if you wish to achieve a pixel perfect drawing of your tiles, you could use 64.0f and 32.0f or 32.0f and 16.0f. The result would be the same.

I personnally like to work with meaningful units rather than pixels; so a tile that is 1 in width makes more sense.

The problem of an isometric world is that it is drawn using classical cartesian, orthogonal coordinates.

Several tiles, like the one above -courtesy of opengameart- are drawn on top of each others. They have transparent sides but they are drawn as classical rectangles.

The problem rises when you click on the map. Which tile is clicked? Take a very close look at this drawing:

In this drawing, we can see there is no simple way to know where the user clicks. Let’s say the user clicks in the region of the isometric tile {1,1}:

The bounding box of the tile {1,1} is of no use: a bit of it belongs to the tile {0,1}, a bit of it to {1,2}… So using bounding boxes will not give you an accurate picking result for isometric world.

## Matrix to the rescue

What we need to do is defining a transform matrix that matches our drawing of the tiles. After all, an isometric world is just a glorified bunch of rectangles rotated by 45 degrees; and with a height divided by 2. So let’s define this matrix. (note: the translation is only there because the origin of the isometric coordinates do not match the origin of the cartesian coordinates. Otherwise, it is completely superfluous)

//create the isometric transform isoTransform = new Matrix4(); isoTransform.idt(); isoTransform.translate(0.0f, 0.25f, 0.0f); isoTransform.scale(1.0f, 0.5f, 1.0f); isoTransform.rotate(0.0f, 0.0f, 1.0f, -45.0f)

Does this work? The answer is **NO**.

It took me a while to figure out why this naive approach didn’t work. The answer lies with your maths from high school. Yes, nothing more. You see, if you take a square and you rotate it by 45 degrees:

Then the width of the shape is not 1.0f anymore but sqrt(2.0f). That is, straight from the Pythagorean theorem.

So, to rescale to the right width, we need to multiply by 1/sqrt(2), or multiply by sqrt(2)/2. Whatever floats your boats, these are the same numbers (~0.707). The height is still half the width. So we get:

//create the isometric transform//create the isometric transform 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 code

The code contains several parts. We have the creation of a tileset from this 256×64 texture (this is GPL’d, I took art from Clint Bellanger to repack it in this simple tileset). and then the creation of a 10×10 map:

//create the isometric transform//load the tileset textureTileset = new Texture("data/tileset.png"); textureTileset.setFilter(TextureFilter.Nearest, TextureFilter.Nearest); tileSet = new TextureRegion[4]; for(int x=0;x<4;x++){ tileSet[x] = new TextureRegion(textureTileset, x*64, 0, 64, 32); } //creat a 10x10 isometric map map = new int[][]{ {0, 0, 0 ,0, 0, 0, 0, 0, 0, 0}, {0, 1, 1 ,1, 1, 1, 1, 1, 1, 0}, {0, 1, 2 ,2, 0, 0, 0, 0, 1, 0}, {0, 1, 2 ,2, 0, 0, 0, 0, 1, 0}, {0, 1, 0 ,0, 0, 0, 0, 0, 1, 0}, {0, 1, 0 ,0, 0, 0, 0, 0, 1, 0}, {0, 1, 0 ,0, 0, 0, 0, 0, 1, 0}, {0, 1, 0 ,0, 0, 0, 0, 0, 1, 0}, {0, 1, 1 ,1, 1, 1, 1, 1, 1, 0}, {0, 0, 0 ,0, 0, 0, 0, 0, 0, 0} };

A simple isometric map renderer (I won’t go into the details of this; you can refer to any tutorial on the web on how to draw an isometric world):

//create the isometric transformprivate void renderMap(){ for (int x = 0; x < 10; x++){ for(int y = 10-1; y >= 0; y--){ float x_pos = (x * tileWidth /2.0f ) + (y * tileWidth / 2.0f); float y_pos = - (x * tileHeight / 2.0f) + (y * tileHeight /2.0f); if(x==pickedTileX && y==pickedTileY) spriteBatch.setColor(1.0f, 0.0f, 0.0f, 1.0f); else spriteBatch.setColor(1.0f, 1.0f, 1.0f, 1.0f); spriteBatch.draw(tileSet[map[x][y]], x_pos, y_pos, tileWidth, tileHeight); } } }

//create the isometric transform@Override public boolean touchDown(int screenX, int screenY, int pointer, intbutton) { touch.set(screenX, screenY, 0); cam.unproject(touch); touch.mul(invIsotransform); pickedTileX = (int)touch.x; pickedTileY = (int)touch.y; return false; }

**No math wizardry, no complex functions: it is just a matrix multiplication!**

Enjoy the power of the matrix and happy coding!

[…] Isometric tile picking […]

Thanks a lot

Hi,

congratulations for your tutorial, it’s very well explained, the images on it remember the diablo series game.

But I need to admit, the math is complex for me.

This tutorial has potencial to become a good mobile game.

Thank you Fabio. I realize it is quite difficult to explain these kind of things. Sometimes it can be quite abstract. My best advice would be to download the code and toy with it.

For the moment I’ll not work with your code, I learn I precious lesson. Finish a game before begin another.

When I fully completes my last game Shuriken Attack, I’ll inspect yours, but since you are the developer of the main code, I don’t think I can create a better isometric game than you.

haha thank you but I am far from being an expert though. I just happen to to like the maths behind games

Great tutorial. I am looking at starting an Iso game but I am looking for the ability to stack tiles for height changes. I was wondering if you have thought about this and how you would go about picking a tile that is technically at a lower point but the screen position is a row or two above.

Hello Doug,

This can be easily achieved once you’ve done the picking. Take this example:

http://uppix.net/7/9/9/72ee9dd97167aa312a614d82771e9.jpg

Tile on the cliff has a height of 2 and real coordinates of 1,5 on the grid. You can then do:

(1,5) + (2,-2) and you get (3,3)

Reply

Hi Tony,

I just wanted to thank you for this great tutorial, it has helped me immensely.

Hi, thanks for this great article, I am trying to drag an image over the isometric map, it works fine on the X axis, but it jumps 2 tiles in the Y axis… I created an image with gimp with an isometric shape of 64×64, and with setSize(1, 0.5f) to render it 64×32( otherwise it is stretched). Then, I use this :

Vector3 screen = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);

camera.unproject(screen);

screen.mul(invIsotransform);

Vector2 iso = new Vector2(screen.x, screen.y);

Vector3 newIso = new Vector3(iso.x, iso.y, 0);

newIso.mul(isoTransform);

Vector2 newScreen = new Vector2((int)newIso.x, (int)newIso.y);

myImg.setPosition(newScreen.x, newScreen.y);

But it jumps 2 tiles in the Y axis… Would you know how to fix this?

I solved it actually, thanks for the article, I can now start my game

I fixed it like that :

if ( objectTaken ){

Vector3 screen = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);

camera.unproject(screen);

screen.mul(invIsotransform);

Vector2 iso = new Vector2(screen.x, screen.y);

Vector3 newScreenTemp = new Vector3((int)iso.x, (int)iso.y, 0);

newScreenTemp.mul(isoTransform);

Vector2 newScreen = new Vector2(newScreenTemp.x, newScreenTemp.y);

curPreview.setPosition(newScreen.x, newScreen.y);

}//objectTaken

Hi, thanks for this great article,

how convert position map to pixel world anh world to map.

thank you!

Hi,

you wanted to say, that your “picking” algorithm is missing a very important thing: height map. You don’t consider height map at all, and not using a height map in an isometric game is not very realistic (unless you want to do all flat terrain, which is usually not the case).

This article is useful for beginners….

http://clintbellanger.net/articles/isometric_math/

Explaining (sorry for my bad English translation)

“Rendering” of sprites / tiles isometrically is a little more complicated than the process explained. The “explained” serves as a working basis and for scenarios where “no sprite” is above / below another (the sprites are just front or back at the same level). In this case the algorithm is clear: follow the drawing order +(Z-X).

But what happens when I have floating elements to a level/height Y?

a-) If the sprites are placed on top of other sprites exactly without overlapping/intersecting with any of them (on the Y axis), the order can be used paint +(Z-X)-Y.

b-) If the sprite “intersects/overlaps” more then 1 sprite simultaneously (in X, Y and/or Z) WE HAVE A PROBLEM: In what order will draw them?. Then we need a complex sorting algorithm to determinate the order. Not to mention when we have “a lot of” floating sprites to be “integrated”.

I, after a long analysis (and much suffering), was able to implement an algorithm. I would never have imagine complexity (honestly I thought it will be easier) of this “affair” and I was finding as I started developing my first game in cocos2d-x 2.5D. An algorithm of this type requires, in the first instance, a “comparison “everything with everything” but is possible to make a lot of optimizations for reducing calculation process so much.

An example (demo) of the algorithm result can be seen here: https://www.youtube.com/watch?v=tU1uJYdxUY4 https://www.youtube.com/watch?v=tBwxX44c6eE

Hello Carlos,

If you look at my game currently in development, you have height and various objects on top of each others (walls, trees, etc) and it all works perfectly fine and it’s drawn correctly without any sort of complex sorting.

The game is actually drawn in layers, which gives good performance (sorting is slow) and allows to cache entire portions of a map into a vertexbufferobject for maximum performance (the parts which will always be drawn behind any other stuff)

This way I can reach 60fps on almost all android devices without bleeding processing power

The math behind this is so easy, matrices are magical, i will try to explain a little bit this article, first you should know I don’t speak a good english…

CONTENT

What you must to understand first?

1. What is a matrix

2. How use a matrix in real-life(games in this case)

3. Where are the matrices normally in videogames?

Why this example work?

WHAT YOU MUST TO UNDERSTAND FIRST?

–

1. WHAT IS A MATRIX

—

A matrix is simply a set of numbers, that is all, only a set of numbers.

Mathematically, a matrix is a rectangular grid of numbers. We can identify a number, or an element, in a matrix by his corresponding row number and column.

Ref 1.1:

https://solarianprogrammer.com/2013/05/22/opengl-101-matrices-projection-view-model/

read the phagrap “MATRIX ALGEBRA REFRESHER”

2. HOW USE A MATRIX iN REAL LIFE(VIDEOGAMES)

—

In videogames you can imagine the matrices like a Pandora box that ransforms objects or points or vertex that are multiplied for them, these Pandora boxes can transform any object in diferent ways, they can translate a point, they can rotate a point, they can scale a point remember translate, rotate or scale, you could read the following for understand how these Pandora boxes work…

Ref 2.1: http://www.mathplanet.com/education/geometry/transformations/transformation-using-matrices

Read all for basic understanding in transformation matrices

Ref 2.2:

https://solarianprogrammer.com/2013/05/22/opengl-101-matrices-projection-view-model/

read the paragraph “THE MODEL MATRIX”

3. WHERE ARE THE MATRICES IN VIDEOGAMES

—

Normally you dont use matrixes in video games but they are in your engine under the hood, for example the camera is really a matrix that is multiplied by another matrix for create what you see in screen, in video games there are three types of matrices commonly used these are .

A. The model matrices, are used for transform the position, rotation and scale of your objects in your world, you could say the model matrix transform points from model coordinates to world or game coordinates, you could also say that the points or vertexes that conform you game objects(model) are now relative to a common coordinate system

B. The view matrix, this matrix make the points of your world relative to the camara, e.g now your world cordinate system is relative to the camera

C. The projection matrix, this matrix make your 3D or 2D world a flat world, this flat world is known as the projection of your game objects to the screen

Ref 3.1:

http://www.codinglabs.net/article_world_view_projection_matrix.aspx

Read for understand more about the model, view and projection matrices

Ref 3.2:

https://solarianprogrammer.com/2013/05/22/opengl-101-matrices-projection-view-model/

Ref 3.3:

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-3-matrices/

more about the model, view and projection matrices plus the homogeneous coordinate system concept

WHY THIS EXAMPLE WORK?

–

Now let’s understand the code behind this article

// this simply is a matrix that we will use for transfor something later

isoTransform = new Matrix4();

// now convert this matrix to identity, e.g now all its element are equal to 1

isoTransform.idt();

// set the translate elements of this matrix to 0 in X, 0.25 in Y and 0 in Z

// now if we multiply a point by this matrix the point will be translated in the

// direction the matrix specify

isoTransform.translate(0.0f, 0.25f, 0.0f);

// if we multiply a point by this matrix that point will be translated and scaled

// we can see also that its scale in Y is the half of 1 this because isometric tiles

// are created with a size proportion of 2 units width : 1 unit height

isoTransform.scale(1.0f, 0.5f, 1.0f);

// now if we multiply a point by this matrix we will get the same point translated

// 0.25 in Y, scaled 0.5 in Y and rotated 45 degrees in clockwise also in Y axis

isoTransform.rotate(0.0f, 0.0f, 1.0f, -45.0f)

Now our dear friend tony say us this wont work,,, ok he explain also why but you should now also this extra info that could be useful

1. The image itself is 1×0.5 units

2. The image contains a picture rotated 45 degrees and scaled 0.5 units in Y

What I want you notice is the image width is one but its content no because its content is rotated

How to solve this?

Using the pythagorea theorem .

Why?

refer to the tony image above for understand why….

The hypotenuse of a triangle is the “hypotenuse squared = opposite leg squared plus adjacent leg squard”

If we solve the hypotenuse

Hypotenuse = squareRoot( power(oppositeLeg) + power(adjacent Leg) )

Our dear friend tony divide 1 against the hypotenuse for get a value between 0 and 1, remember his tiles are 1×0.5, you could also devide against (power(oppositeLeg) + power(adjacent Leg)) for the same reason

Now the new version of the code

// just the matrix and some transformations

isoTransform = new Matrix4();

isoTransform.idt();

isoTransform.translate(0.0f, 0.25f, 0.0f);

// this is what I just said about the hypotenuse

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);

Now follow the most important part like tony said

public boolean touchDown(int screenX, int screenY, int pointer, intbutton) {

// we hava a vector3 for store the position in screen where user clicks

touch.set(screenX, screenY, 0);

// unproject convert from screen coordinate to world coordinates

cam.unproject(touch);

// remember when I said a matrix in video games is like a Pandora box that

// transform points when they are multiplied by…. ok here is that pandora box

// working, we’re getting a screen coordinate converted to world

// coordinates(remember this is just a point) and later we are multiplying it

// by a matrix that will translate, scale and rotate any point that

// it to be multiplied by the matrix

touch.mul(invIsotransform);

// now we only need to cast the values and voila!!!

pickedTileX = (int)touch.x;

pickedTileY = (int)touch.y;

return false;

}

great explanation.

How to work with isometric map with layers and collision detection. Plz help

Can someone please explain this line better:

isoTransform.scale((float)(Math.sqrt(2.0) / 2.0), (float)(Math.sqrt(2.0) / 4.0), 1.0f);

I need to change this to use tiles that are 128×64 and im not sure how.

Hi Guys,

I am trying to move the camera in this example, but i cannot get success

I used cam.lookAt(…) and other methods, no one works.

.

Could you please provide me an example about moving cameras in this isometric scenario. I cannot find good documentation or working examples

Thanks!

Hi Ale,

If you’re using LibGDX, you can adjust the camera’s position by adjusting camera.position. Example:

if (Gdx.input.isKeyPressed(Input.Keys.E)) {

camera.position.x += 2;

} else if (Gdx.input.isKeyPressed(Input.Keys.Q)) {

camera.position.x -= 2;

}

Good luck!

Max

Oh, and don’t forget to update your camera!

if (Gdx.input.isKeyPressed(Input.Keys.E)) {

camera.position.x += 2;

camera.update();

} else if (Gdx.input.isKeyPressed(Input.Keys.Q)) {

camera.position.x -= 2;

camera.update();

}

Good blog! I really love how it is easy on my eyes and the data are well written. I am wondering how I could be notified whenever a new post has been made. I have subscribed to your feed which must do the trick! Have a nice day! dddefffbcbceaded

Hello!online pharmacy cialis

Very informative blog post.Really thank you! Keep writing. bebbdkkdagdedegd

I appreciate your wordpress web template, exactly where did you down load it through?

How To Buy Cheap Generic Ceclor 500mg

Write more, thats all I have to say. Literally, it seems as though you relied on the video to make your point. You clearly know what youre talking about, why throw away your intelligence on just posting videos to your weblog when you could be giving us something enlightening to read?

I loved your blog article. Really Cool.

what are some superior and in demand websites for blogs? ?? .

I value the post.Thanks Again. Awesome.

I truly prize your function, Wonderful post.

I’m glad that it turned out so effectively and I hope it will continue in the future because it is so worthwhile and meaningful to the community.

weblog. Loads of gratitude sharing.

My brother recommended I may like this website. He used to be totally right. This post truly made my day. You can not consider simply how so much time I had spent for this info! Thanks!

Excellently written writeup, doubts all bloggers offered the same content material because you, the internet is actually a greater location. Please maintain it up!

Hahahahahahaha, this politics related YouTube video is really so comical, I loved it. Thanks in favor of sharing this.

It’s a mammoth playground built of mountains, hills, lakes, rivers, valleys, woodlands,and beaches.

It’s truly a great and useful piece of information. I’m satisfied that you shared this helpful information with us. Please stay us informed like this. Thank you for sharing.

Mudbox is a software for 3D sculpting and painting which is developed

I was looking through some of your blog posts on this internet site and I conceive this web site is rattling informative ! Keep on posting .

You are my inspiration , I have few web logs and very sporadically run out from to brand.

Appreciate it for helping out, great information.

Howdy very nice web site!! Guy .. Excellent .. Superb .. I’ll bookmark your web site and take the feeds additionallyI am glad to search out so many helpful info here in the put up, we want develop more techniques in this regard, thanks for sharing.

Farmville farms even include free gift that is especially

Hi, Neat post. There is a problem with your web site in internet explorer, would check this IE still is the market leader and a large portion of people will miss your magnificent writing because of this problem.

I like the valuable info you provide in your articles. I will bookmark your blog and check again here regularly. I am quite certain I’ll learn a lot of new stuff right here! Best of luck for the next!

I’ve long suggested that people seeking to gett a good understanding of this speciific topic spread their research acrooss many blogs

I do trust all of the ideas you’ve presented in your post. They’re very convincing and can certainly work. Nonetheless, the posts are very short for beginners. May just you please lengthen them a bit from next time? Thanks for the post.

I have been surfing online more than 3 hours today, yet I never found any interesting article like yours. It is pretty worth enough for me. In my view, if all webmasters and bloggers made good content as you did, the internet will be much more useful than ever before.

Howdy! I basically would like to give a huge thumbs up for the good data you’ve got here on this post. I will probably be coming once again to your weblog for far more soon.

This did the trick for screen to iso, but how about cartesian to iso? can’t make it work. anyone?

So i have libgdx and I use a camera, the thing is this article help me to manage screen clicks to iso, but now I have the problem to convert camera coords to Iso, that is cartesian to iso I believe?

Hey esto es un gran poste. Puedo utilizar una porcin en ella en mi sitio? Por supuesto ligara a su sitio as que la gente podra leer el artculo completo si ella quiso a. Agradece cualquier manera.

You are my inhalation, I have few web logs and rarely run out from post

Hi there! This is my first visit to your blog! We are a group of volunteers and starting a new initiative in a community in the same niche. Your blog provided us beneficial information to work on. You have done a marvellous job!

Hi there, I found your web site by the use of Google while searching for a similar matter, your site came up, it seems to be good. I’ve bookmarked it in my google bookmarks.

Maintain the excellent job mate. This web blog publish shows how well you comprehend and know this subject.

It’s perfect time to make some plans for the long run and it is time to be happy. I have learn this publish and if I may I want to suggest you few attentiongrabbing things or advice. Maybe you could write next articles regarding this article. I desire to read even more things about it!

I really appreciate this post. I’ve been looking all over for this! Thank goodness I found it on Bing. You’ve made my day! Thanks again!

This is really attentiongrabbing, You’re a very professional blogger. I have joined your rss feed and sit up for in search of extra of your fantastic post. Also, I have shared your site in my social networks!

That is some inspirational stuff. Never knew that opinions could be this varied. Be certain to keep writing.

Hello! Do you use Twitter? I’d like to follow you if that would be okay. I’m undoubtedly enjoying your blog and look forward to new posts.

I will immediately clutch your rss feed as I can not to find your email subscription link or enewsletter service. Do you have any? Please let me know in order that I may just subscribe. Thanks.

I got what you intend, thankyou for putting up.Woh I am glad to find this website through google. It is a very hard undertaking to seek to please everybody. by Publilius Syrus.

Please add more movies related to cooking if you have, because I wish for to learn more and more about all recipes of cooking.

I will immediately clutch your rss feed as I can not to find your email subscription link or enewsletter service. Do you have any? Please let me know in order that I may just subscribe. Thanks.

What’s up it’s me, I am also visiting this site daily, this website is actually pleasant and the visitors are really sharing fastidious thoughts.