# Collision Detection on floor tiles Isometric game

I am having a very hard to time figuring out a bug in my code. It should have taken me 20 minutes but instead I've been working on it for over 12 hours. I am writing a isometric tile based game where the characters can walk freely amongst the tiles, but not be able to cross over to certain tiles that have a collides flag. Sounds easy enough, just check ahead of where the player is going to move using a Screen Coordinates to Tile method and check the tiles array using our returned xy indexes to see if its collidable or not. if its not, then don't move the character. The problem I'm having is my Screen to Tile method isn't spitting out the proper X,Y tile indexes. This method works flawlessly for selecting tiles with the mouse. NOTE: My X tiles go from left to right, and my Y tiles go from up to down. Reversed from some examples on the net. Here's the relevant code:

    public Vector2 ScreentoTile(Vector2 screenPoint) {
//Vector2 is just a object with x and y float properties
//camOffsetX,Y are my camera values that I use to shift everything but the
//current camera target when the target moves
//tilescale = 128, screenheight = 480, the -46 offset is to center
// vertically + 16 px for some extra gfx in my tile png
Vector2 tileIndex = new Vector2(-1,-1);

screenPoint.x -= camOffsetX;
screenPoint.y = screenHeight - screenPoint.y - camOffsetY - 46;

tileIndex.x = (screenPoint.x / tileScale) + (screenPoint.y / (tileScale / 2));
tileIndex.y = (screenPoint.x / tileScale) - (screenPoint.y / (tileScale / 2));

return tileIndex;
}


The method that calls this code is:

    private void checkTileTouched () {

if (Gdx.input.justTouched()) {
if (last.x >= 0 && last.x < levelWidth && last.y >= 0 && last.y < levelHeight) {
if (lastSelectedTile != null) lastSelectedTile.setColor(1, 1, 1, 1);
Sprite sprite = levelTiles[(int) last.x][(int) last.y].sprite;
sprite.setColor(0, 0.3f, 0, 1);
lastSelectedTile = sprite;
}
}
if (touchDown) {
float moveX=0,moveY=0;
Vector2 pos = new Vector2();

if (player.direction == direction_left) {
moveX =  -(player.moveSpeed);
moveY =  -(player.moveSpeed / 2);
Gdx.app.log("Movement", String.valueOf("left"));
} else if (player.direction == direction_upleft) {
moveX = -(player.moveSpeed);
moveY = 0;
Gdx.app.log("Movement", String.valueOf("upleft"));
} else if (player.direction == direction_up) {
moveX = -(player.moveSpeed);
moveY = player.moveSpeed / 2;
Gdx.app.log("Movement", String.valueOf("up"));
} else if (player.direction == direction_upright) {
moveX = 0;
moveY = player.moveSpeed;
Gdx.app.log("Movement", String.valueOf("upright"));
} else if (player.direction == direction_right) {
moveX = player.moveSpeed;
moveY = player.moveSpeed / 2;
Gdx.app.log("Movement", String.valueOf("right"));
}  else if (player.direction == direction_downright) {
moveX = player.moveSpeed;
moveY = 0;
Gdx.app.log("Movement", String.valueOf("downright"));
}  else if (player.direction == direction_down) {
moveX = player.moveSpeed;
moveY = -(player.moveSpeed / 2);
Gdx.app.log("Movement", String.valueOf("down"));
}  else if (player.direction == direction_downleft) {
moveX = 0;
moveY = -(player.moveSpeed);
Gdx.app.log("Movement", String.valueOf("downleft"));
}
//Player.moveSpeed is 1
//tileObjects.x is drawn in the center of the screen (400px,240px)
// the sprite width is 64, height is 128

testX = moveX * 10;
testY = moveY * 10;

testX += tileObjects.get(player.zIndex).x + tileObjects.get(player.zIndex).sprite.getWidth() / 2;
testY += tileObjects.get(player.zIndex).y + tileObjects.get(player.zIndex).sprite.getHeight() / 2;

moveX += tileObjects.get(player.zIndex).x + tileObjects.get(player.zIndex).sprite.getWidth() / 2;
moveY += tileObjects.get(player.zIndex).y + tileObjects.get(player.zIndex).sprite.getHeight() / 2;

pos = ScreentoTile(new Vector2(moveX,moveY));
Vector2 pos2 = ScreentoTile(new Vector2(testX,testY));

if (!levelTiles[(int) pos2.x][(int) pos2.y].collides) {
Vector2 newPlayerPos = ScreentoTile(new Vector2(moveX,moveY));
CenterOnCoord(moveX,moveY);
player.tileX = (int)newPlayerPos.x;
player.tileY = (int)newPlayerPos.y;
}
}
}


When the player is moving to the left (downleft-ish from the viewers point of view), my Pos2 X values decrease as expected but pos2 isnt checking ahead on the x tiles, it is checking ahead on the Y tiles(as if we were moving DOWN, not left), and vice versa, if the player moves down, it will check ahead on the X values (as if we are moving LEFT, instead of DOWN). instead of the Y values.

I understand this is probably the most confusing and horribly written post ever, but I'm confused myself so I'm having a hard time explaining it to others lol. if you need more information please ask!! I'm so frustrated after over 12 hours of working on it I'm about to give up.

• Does it occur only when moving left or does this consistently happen for all directions? – Mike Cluck Nov 23 '11 at 21:50
• Yes every direction. For instance: if the character is moving down we shouldnt be looking ahead on the X axis (running left to right) but the Y should be looking ahead moveY * 6, but its applying moveY * 6 to X instead of Y. I tried feeding moveX to Y and moveY to X, and that returns the right tile numbers as far as looking ahead goes,which shouldnt be the case, but it also produces incorrect collision detection moving diagonally. It puzzles me that my code for actually making the character walk in the direction they are looking works perfectly. but when I try and look ahead, it fails – Anivrom Nov 23 '11 at 23:16
• Well, it's not a full scale answer but it looks like you're only updating the characters position if in fact there is no collision. However, you've already calculated the characters new position before this. It seems like the testX and testY are moot and you would just want to check with your characters hypothetical new position, since it seems to be producing the proper coordinates being that it's moving properly. Unless of course I'm missing something vital in your code. – Mike Cluck Nov 24 '11 at 18:41
• Well the whole point is not to update the players position if the future position (exaggerated by a multiple of 6 and returned as pos2) is going to end up on a collidable tile. the problem is its not returning the proper values. I'll have to add some screenshots with value overlays – Anivrom Nov 25 '11 at 2:37
• I understand that. But you're measuring moveX and moveY then if there is no collision at pos2, move using moveX and moveY. Why not just use that measurement since that actually represents your next position? I guess I don't understand why you're making two different measurements for the same possible position. – Mike Cluck Nov 26 '11 at 15:32

I realize this question is over 2 years old, but I am going to answer it anyway.

Your screen dimensions are not equal in length and height and you are using screen dimensions to project into levelTile. When you scale both moveX and moveY by 10, it causes your forward projection to become skewed.

In order for your forward projection to be accurate there are a couple of solutions.

1)You could scale each component relative to the screens aspect ration. Looking at your comment, the screen is 800x480. 480/800 = 0.6.

testX = moveX * 10;
testY = moveY * 6;


2) Calculate the movement vector relative to the levelTiles, then scale that and test for collision.

Vector2 playerTile = new Vector2(player.tileX, player.tileY);
Vector2 moveToTile = ScreenToTile(new Vector2(moveX, moveY));
Vector2 tileMovementVector = playerTile - moveToTile;

// set the amount of forward projection (I am doubling the movement,
// but set this to what is relevant)
float projectionFactor = 2.0f;
Vector2 forwardTileProjection = tileMovementVector * projectionFactor;

if (!levelTiles[(int)forwardTilePojection.x][(int)forwardTilePojection.y].collides) {
...
}