Picking Tile in staggered isometric map

Hello!
I have been looking and trying for quite a while now, but can’t seem to work out an algorithm for figuring out which tile is selected on a staggered isometric map using 64x32 tiles with a diamond shape inside.

Here is a pic of my map…

The first row is drawn, then the x is offset to the right by 32 and the next row is drawn.

Anyone have any good math skills to throw some algorithms my way for this?
Thanks for any help!

PS: My math isn’t exactly top notch, so please keep that in mind. :slight_smile:

You can indeed solve this with a little maths.
In my isometric games, I use the following code to calculate where to draw a given tile:


int screenx = (int)(TILE_WIDTH * (tilex - tiley)/2.0);
int screeny = (int)(TILE_HEIGHT * (tilex + tiley)/2.0);

  • screenx and screeny are the position on screen
  • tilex and tiley are the tile position in the game world
  • in your case, TILE_WIDTH = 64 and TILE_HEIGHT = 32
  • some games may include a camera offset, but in principal they all work the same way

To determine which tile is selected on screen, you can use simultaneous equations to find tilex and tiley. Basically, make tilex the subject of the first equation, and tiley the subject of the second. I can explain this bit in more detail if you like…
Solving the simultaneous equations results in the following code:


int tilex = (int)(screenx/TILE_WIDTH + screeny/TILE_HEIGHT);
int tiley = (int)(screeny/TILE_HEIGHT - screenx/TILE_WIDTH);

Thanks for the input Dapy,

I’m kind of confused on what tileX and tileY are returning in this formula…
int tilex = (int)(screenx/TILE_WIDTH + screeny/TILE_HEIGHT);
int tiley = (int)(screeny/TILE_HEIGHT - screenx/TILE_WIDTH);

are those the coordinates for the tile that was clicked?

I dont have any offsets, so I am starting my drawing at 0,0 on the screen
I am using this for drawing my tiles…

for (var i = 0; i < rows; ++i) {
	for (var j = 0; j < cols; ++j) {
		tTile._y = i*16;
		// handle odd and even rows differently
		if (i % 2) {
		  // Even Row
		  tTile._x = (j*64)+32;
		} else {
		  // odd row
		  tTile._x = j*64;
		}
	}
}

PS: should also explain that I’m not very good at abstract logic either, hehehe.

Yes - tilex and tiley are the co-ordinates of the clicked tile.

How do you store information about tiles in your game?

In my game, tile data is stored in a 2-dimensional array, something like this:


Tile[][] tileData = new Tile[TOTAL_COLUMNS][TOTAL_ROWS];

Therefore I can access the tile data like this:


// find which tile the player has clicked
int tilex = (int)(screenx/TILE_WIDTH + screeny/TILE_HEIGHT);
int tiley = (int)(screeny/TILE_HEIGHT - screenx/TILE_WIDTH);

// respond to the click depending on what is in that tile
if (tileData[tiley][tilex] == Tile.BLOB) {
  // do something to BLOB tile
} else if (...) {
  // ... etc etc...

I create my tiles from a Tile object that has individual fields. I do store the x and y of the tile, but that just references the top left corner of the 64x32 tile, where it will be drawn. Plus I would have to iterate through all tiles until that tile is matched which would still be pointing to the tiles drawing origin.

Of course this is in Flash, but the ideas are still the same. The formula for picking a tile in a diamond shape isometric map that was given by dishmoth in this post…


worked great for the diamond shape isometric map. But trying to chop that up to make it work for a staggered isometric map is proving to be quite a challenge. The issue I believe is in the staggering of the rows.

I will keep staring at it until my eyes fall out in great goobs of goo

;D

Danny02, where are you? ^^

Ah, now I understand!
The technique I described is pretty much the same as dishmoth’s - it works for ‘diamond’ isometric, but not for ‘staggered’.

The following link explains how you might solve the problem for ‘staggered’ isometric maps:

http://www.gamedev.net/page/resources/_/technical/game-programming/isometric-n-hexagonal-maps-part-i-r747

Look for the heading ‘Mouse Matters’.

I appreciate the help. It being the work week, I didn’t get a chance to really put some time into any solution and I definitely am not going to post the embarassing hack I was attempting.

I did get a plug and play solution involving some math equations that are quite a bit beyond me that I will post for anyone running into the same situation. It works great!

dawsonk


Maybe try something like this…
    
    var tileW = 64;
    var tileH = 32;
    var rows = 8;
    var cols = 4;

    for (var i = 0; i < rows; ++i) {
            for (var j = 0; j < cols; ++j) {
                    tTile = _root.attachMovie("Tile", "R" + i + "C" + j, _root.getNextHighestDepth());
                    tTile._x = (tileW * j) + ((i % 2 == 1) ? 32 : 0);
                    tTile._y = (tileH / 2) * i;
            }
    }
    onMouseDown = function () {
            var ax, ay, bx, by;
            var cx = _xmouse;
            var cy = _ymouse;
            var posX = (_xmouse / 32) >> 0;
            var posY = (_ymouse / 16) >> 0;
            if ((posX % 2) == (posY % 2)) {
                    ax = (posX) * 32;
                    ay = (posY + 1) * 16;
                    bx = (posX + 1) * 32;
                    by = (posY) * 16;
                    if (getPos(ax, ay, bx, by, cx, cy) < 0) {
                            trace(((posY / 1 >> 0) - 1) + " : " + ((posX / 2 >>0) + ((((posY / 1 >> 0) - 1) % 2 == 0) ? 0 : -1)));
                    } else {
                            trace((posY / 1 >> 0) + " : " + (posX / 2 >> 0));
                    }
            } else {
                    ax = (posX) * 32;
                    ay = (posY) * 16;
                    bx = (posX + 1) * 32;
                    by = (posY + 1) * 16;
                    if (getPos(ax, ay, bx, by, cx, cy) < 0) {
                            trace(((posY / 1 >> 0) - 1) + " : " + (posX / 2 >>0));
                    } else {
                            trace((posY / 1 >> 0) + " : " + ((posX / 2 >> 0) +((((posY / 1 >> 0) - 1) % 2 == 0) ? -1 : 0)));
                    }
            }
    };
    function getPos($ax, $ay, $bx, $by, $cx, $cy) {
            // below = 1, above = -1, on = 0;
            var slope = ($by - $ay) / ($bx - $ax);
            var yIntercept = $ay - $ax * slope;
            var cSolution = (slope * $cx) + yIntercept;
            if (slope != 0) {
                    if ($cy > cSolution) {
                            return $bx > $ax ? 1 : -1;
                    }
                    if ($cy < cSolution) {
                            return $bx > $ax ? -1 : 1;
                    }
                    return 0;
            }
            return 0;
    }