2D isometric picking

Posted by Bikonja on Game Development See other posts from Game Development or by Bikonja
Published on 2012-12-02T13:10:06Z Indexed on 2012/12/02 17:22 UTC
Read the original article Hit count: 247

Filed under:
|

I'm trying to implement picking in my isometric 2D game, however, I am failing.

First of all, I've searched for a solution and came to several, different equations and even a solution using matrices. I tried implementing every single one, but none of them seem to work for me.

The idea is that I have an array of tiles, with each tile having it's x and y coordinates specified (in this simplified example it's by it's position in the array). I'm thinking that the tile (0, 0) should be on the left, (max, 0) on top, (0, max) on the bottom and (max, max) on the right.

I came up with this loop for drawing, which googling seems to have verified as the correct solution, as has the rendered scene (ofcourse, it could still be wrong, also, forgive the messy names and stuff, it's just a WIP proof of concept code)

// Draw code
int col = 0;
int row = 0;
for (int i = 0; i < nrOfTiles; ++i)
{
    // XOffset and YOffset are currently hardcoded values, but will represent camera offset combined with HUD offset
    Point tile = IsoToScreen(col, row, TileWidth / 2, TileHeight / 2, XOffset, YOffset);
    int x = tile.X;
    int y = tile.Y;

    spriteBatch.Draw(_tiles[i], new Rectangle(tile.X, tile.Y, TileWidth, TileHeight), Color.White);

    col++;
    if (col >= Columns) // Columns is the number of tiles in a single row
    {
        col = 0;
        row++;
    }
}

// Get selection overlay location (removed check if selection exists for simplicity sake)
Point tile = IsoToScreen(_selectedTile.X, _selectedTile.Y, TileWidth / 2, TileHeight / 2, XOffset, YOffset);

spriteBatch.Draw(_selectionTexture, new Rectangle(tile.X, tile.Y, TileWidth, TileHeight), Color.White);
// End of draw code

public Point IsoToScreen(int isoX, int isoY, int widthHalf, int heightHalf, int xOffset, int yOffset)
{
    Point newPoint = new Point();

    newPoint.X = widthHalf * (isoX + isoY) + xOffset;
    newPoint.Y = heightHalf * (-isoX + isoY) + yOffset;

    return newPoint;
}

This code draws the tiles correctly. Now I wanted to do picking to select the tiles. For this, I tried coming up with equations of my own (including reversing the drawing equation) and I tried multiple solutions I found on the internet and none of these solutions worked. Trying out lots of solutions, I came upon one that didn't work, but it seemed like an axis was just inverted. I fiddled around with the equations and somehow managed to get it to actually work (but have no idea why it works), but while it's close, it still doesn't work. I'm not really sure how to describe the behaviour, but it changes the selection at wrong places, while being fairly close (sometimes spot on, sometimes a tile off, I believe never more off than the adjacent tile).

This is the code I have for getting which tile coordinates are selected:

public Point? ScreenToIso(int screenX, int screenY, int tileHeight, int offsetX, int offsetY)
{ 
    Point? newPoint = null;

    int nX = -1;
    int nY = -1;

    int tX = screenX - offsetX;
    int tY = screenY - offsetY;

    nX = -(tY - tX / 2) / tileHeight;
    nY = (tY + tX / 2) / tileHeight;

    newPoint = new Point(nX, nY);

    return newPoint;
}

I have no idea why this code is so close, especially considering it doesn't even use the tile width and all my attempts to write an equation myself or use a solution I googled failed.

Also, I don't think this code accounts for the area outside the "tile" (the transparent part of the tile image), for which I intend to add a color map, but even if that's true, it's not the problem as the selection sometimes switches on approx 25% or 75% of width or height.

I'm thinking I've stumbled upon a wrong path and need to backtrack, but at this point, I'm not sure what to do so I hope someone can shed some light on my error or point me to the right path.

It may be worth mentioning that my goal is to not only pick the tile. Each main tile will be divided into 5x5 smaller tiles which won't be drawn seperately from the whole main tile, but they will need to be picked out. I think a color map of a main tile with different colors for different coordinates within the main tile should take care of that though, which would fall within using a color map for the main tile (for the transparent parts of the tile, meaning parts that possibly belong to other tiles).

© Game Development or respective owner

Related posts about isometric

Related posts about picking