Right now I'm attempting to build an engine for rendering a tile based map with an isometric projection. Rendering the map seems to be working now but at the moment, I'm frustrated trying to figure out how to select a tile. For normal 2D this is simple, but I can't seem to figure out how this needs to be done. Since an isometric tile is a squished diamond shape, you need to find out if the click was actually on the tile, or one of the adjacent tiles. I've tried a bunch of methods such as checking if the click was in the polygon, then seeing which quadrant the click was in if the test failed. I've also tried checking if the click was in the polygon, then if the click was outside to check if the click was inside any of the eight adjacent tiles. I really don't know where to go with this so I'll post my code here.
Any suggestions would be appreciated.
Thanks.
package com.isoTest;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import java.awt.Point;
import java.awt.Polygon;
public class Map {
private int[][] data;
private Texture img, img2;
private int TILE_HEIGHT = 32;
private int TILE_WIDTH = 64;
private int TILE_HEIGHT_HALF = TILE_HEIGHT/2;
private int TILE_WIDTH_HALF = TILE_WIDTH/2;
private int MAP_WIDTH;
private int MAP_HEIGHT;
private int X_OFFSET;
public Map() {
img = new Texture(Gdx.files.internal("isograss1.png"));
img2 = new Texture(Gdx.files.internal("redcube.png"));
data = new int[][]{{1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}};
MAP_WIDTH = data[0].length*TILE_WIDTH;
MAP_HEIGHT = (data[0].length*TILE_HEIGHT/2)+(16*data.length);
X_OFFSET = ((data.length-1)*TILE_HEIGHT);
}
public Vector2 cartToIso(Vector2 init){
Vector2 iso = new Vector2();
iso.x = (((init.x - init.y) * TILE_WIDTH/2))+X_OFFSET;
iso.y = MAP_HEIGHT-TILE_HEIGHT-((init.x + init.y) * TILE_HEIGHT/2);
return iso;
}
public Vector2 cartToIso(int x, int y){
Vector2 iso = new Vector2();
iso.x = (((x - y) * TILE_WIDTH/2))+X_OFFSET;
iso.y = MAP_HEIGHT-TILE_HEIGHT-((x + y) * TILE_HEIGHT/2);
return iso;
}
public Vector2 isoToCart(Vector2 init){
Vector2 cart = new Vector2();
init.x = init.x-X_OFFSET;
init.y = init.y-MAP_HEIGHT;
cart.x = (init.x / (TILE_WIDTH/2) + init.y / (TILE_HEIGHT/2)) /2;
cart.y = (init.y / (TILE_HEIGHT/2) -(init.x / (TILE_WIDTH/2))) /2;
return cart;
}
public Vector2 isoToCart(int x, int y){
Vector2 cart = new Vector2();
x = x-X_OFFSET;
y = y-MAP_HEIGHT;
cart.x = (x / (TILE_WIDTH/2) + y / (TILE_HEIGHT/2)) /2;
cart.y = (y / (TILE_HEIGHT/2) -(x / (TILE_WIDTH/2))) /2;
return cart;
}
public void render(SpriteBatch batch){
for(int i = 0; i < data.length; i++){
for(int j = 0; j < data[i].length;j++){
if(data[i][j] == 0){
Vector2 coords = cartToIso(j, i);
batch.draw(img,coords.x,coords.y);
}else if(data[i][j] == 1){
Vector2 coords = cartToIso(j, i);
batch.draw(img2,coords.x,coords.y);
}
}
}
}
/**
* @param clickX mouse position x
* @param clickY mouse position y
*/
public void getTileAt(int clickX, int clickY){
Vector2 coords = isoToCart(clickX,clickY);
System.out.println("Isometric coordinates: "+coords.x+","+coords.y);
//get actual tile for reference
Vector2 tileCoords = cartToIso(coords);
int centerX = (int)tileCoords.x + (TILE_WIDTH/2);
int centerY = (int)tileCoords.y + (TILE_HEIGHT/2);
Point p = new Point(clickX,Gdx.graphics.getHeight()-clickY);
Point p1 = new Point(centerX,centerY+TILE_HEIGHT_HALF);
Point p2 = new Point(centerX-TILE_WIDTH_HALF,centerY);
Point p3 = new Point(centerX,centerY-TILE_HEIGHT_HALF);
Point p4 = new Point(centerX+TILE_WIDTH_HALF,centerY);
Polygon diamond = new Polygon();
diamond.addPoint(p1.x,p1.y);
diamond.addPoint(p2.x,p2.y);
diamond.addPoint(p3.x,p3.y);
diamond.addPoint(p4.x,p4.y);
System.out.println("Point at: " + p1.x+","+p1.y);
System.out.println("Point at: " + p2.x+","+p2.y);
System.out.println("Point at: " + p3.x+","+p3.y);
System.out.println("Point at: " + p4.x+","+p4.y);
System.out.println(diamond.contains(p));
if(!diamond.contains(p)){
if(clickX>centerX){
if(clickY>centerY){
coords.y--;
}else if(clickY < centerY){
coords.x++;
}
}else if(clickX < centerX){
if(clickY>centerY){
coords.x--;
}else if(clickY < centerY){
coords.y++;
}
}
System.out.println("Correction made!");
System.out.println("Isometric coordinates: "+coords.x+","+coords.y);
}
System.out.println("Click: "+clickX+","+(Gdx.graphics.getHeight()-clickY));
if(data[(int)coords.y][(int)coords.x] == 0){
data[(int)coords.y][(int)coords.x] = 1;
}else{
data[(int)coords.y][(int)coords.x] = 0;
}
}
public int getMAP_WIDTH() {
return MAP_WIDTH;
}
public void setMAP_WIDTH(int MAP_WIDTH) {
this.MAP_WIDTH = MAP_WIDTH;
}
public int getMAP_HEIGHT() {
return MAP_HEIGHT;
}
public void setMAP_HEIGHT(int MAP_HEIGHT) {
this.MAP_HEIGHT = MAP_HEIGHT;
}
}