Collision detection with Java, Slick2D and Tiled Map Editor

advertisements

I've been stuck on collision detection and how to handle it for a VERY long time. I need help understanding how to use collision detection with Tiled map editor. I have the TMX file parsed and displayed with a player, camera and keyboard movement. I'm not sure how to about doing to collision. My map has 2 layers, one for grass and tiles you can walk on, the other is objectLayer. I've seen people saying I should loop through all the tiles in an object layer and assign rectangles to them. I've got NO idea how to do that and I'm looking for some insight.

My main question is: how do I loop through my layer and get all the tiles and assign rectangles to them.

Game Class:

    public class Game extends BasicGameState {

Player player;
Camera cam;
Map map = new Map();

public void init(GameContainer container, StateBasedGame sbg) throws SlickException {
    map.init();
    cam = new Camera(0, 0);
    player = new Player(new Image("res/textures/player.png"), container.getWidth() / 2, container.getHeight() / 2, 32, 32);
}

public void update(GameContainer container, StateBasedGame sbg, int delta) throws SlickException {
    cam.tick(player);
    player.update(container, delta, map);
}

public void render(GameContainer container, StateBasedGame sbg, Graphics g) throws SlickException {
    g.translate(-cam.getX(), -cam.getY());
        map.render();
        player.render(g);
    g.translate(cam.getX(), cam.getY());
}

public int getID() {
    return 1;
}

}

Player Class:

    public class Player {

float x, y;

int width, height;
double velX = 0.4;
double velY = 0.4;

Image img;

public Player(Image img, float x, float y, int width, int height) {
    this.img = img;
    this.x = x;
    this.y = y;
    this.width = width;
    this.height = height;
}

public void init() throws SlickException {

}

public void update(GameContainer container, int delta, Map map) {
    Input input = container.getInput();

    if (input.isKeyDown(Input.KEY_D)) x += velX;
    if (input.isKeyDown(Input.KEY_A)) x -= velX;
    if (input.isKeyDown(Input.KEY_W)) y -= velY;
    if (input.isKeyDown(Input.KEY_S)) y += velY;

}

public void render(Graphics g) {
    //g.scale(-2, -2);
    g.drawImage(img, x, y);
}

public float getX() {
    return x;
}

public float getY() {
    return y;
}

}

Map class:

    public class Map {

TiledMap map;

public void init() throws SlickException {
    map = new TiledMap("res/map/zenith.tmx");
}

public void render() throws SlickException {
    map.render(0, 0);
}

}


I'm not too familiar with the methods exactly for getting the tile, but it's definitely in the Javadoc. http://slick.ninjacave.com/javadoc/

For checking collisions against a player, you need to change your movement to check whether the new location of the player is going to have a collision, otherwise you'll get stuck on them.

public void update(GameContainer container, int delta, Map map) {
    Input input = container.getInput();
    float dx = 0, dy = 0;
    // add to dx and dy instead of moving the player straight away.
    if (input.isKeyDown(Input.KEY_D)) dx += velX;
    if (input.isKeyDown(Input.KEY_A)) dx -= velX;
    if (input.isKeyDown(Input.KEY_W)) dy -= velY;
    if (input.isKeyDown(Input.KEY_S)) dy += velY;
    // here we check the collisions, you can fiddle with this if statement and it'll behave differently.
    if(dx != 0 || dy != 0){
        if(map.checkCollision(x+dx,y+y){
           x+=dx;
           y+=dy;
        }
    }
}

As for checking the collision itself you need a new method in your map class that creates a rectangle for the player and checks against a 2D array inside the map class which holds your collisions. You can populate this array when the map is intialised by looping through your Tiled map through the layer you need and checking if the tile is a collision with getTile(x,y). If the tile has the correct properties for a collision you create a rectangle in that location in your 2D array with something like this:

collisionArray[x][y] = new Rectangle(x,y,TILEWIDTH,TILEHEIGHT);

You can now check for the collision inside

map.checkCollision(x,y)

and with a rectangle created for the player using

Rectangle player = new Rectangle(x,y,PLAYERWIDTH,PLAYERHEIGHT);

Putting it all together you can then check for an intersection with any tiles in the collision array with .intersect(r) as mentioned earlier and map.collision can return true to the player which should stop movement of the player.

I hope that wasn't too convoluted, the javadoc is very helpful and Kevin Glass wrote a thing about checking collisions with just 2D arrays, with varying collision box sizes. http://www.cokeandcode.com/main/tutorials/tile-maps/