Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am trying to set up collision detection in Slick2D based on a tilemap. I currently have two layers on the maps I'm using, a background layer, and a collision layer. The collision layer has a tile with a 'blocked' property, painted over the areas the player can't walk on. I have looked through the Slick documentation, but do not understand how to read a tile property and use it as a flag for collision detection.

My method of 'moving' the player is somewhat different, and might affect how collisions are handled. Instead of updating the player's location on the window, the player always stays in the same spot, updating the x and y the map is rendered at. I am working on collisions with objects by restricting the player's movement when its hitbox intersects an object's hitbox. The code for the player hitting the right side of an object, for example, would look like this:

if(Player.bounds.intersects(object.bounds)&&(Player.x<=(object.x+object.width+0.5))&&Player.isMovingLeft){
        isInCollision=true;
        level.moveMapRight();
    }
    else if(Player.bounds.intersects(object.bounds)&&(Player.x<=(object.x+object.width+0.5))&&Player.isMovingRight){
        isInCollision=true;
        level.moveMapRight();
    }
    else if(Player.bounds.intersects(object.bounds)&&(Player.x<=(object.x+object.width+0.5))&&Player.isMovingUp){
        isInCollision=true;
        level.moveMapRight();
    }
    else if(Player.bounds.intersects(object.bounds)&&(Player.x<=(object.x+object.width+0.5))&&Player.isMovingDown){
        isInCollision=true;
        level.moveMapRight();
    }

and in the level's update code:

if(!Player.isInCollision)
        Player.manageMovementInput(map, i);

However, this method still has some errors. For example, when hitting the object from the right, the player will move up and to the left, clipping through the object and becoming stuck inside its hitbox. If there is a more effective way of handling this, any advice would be greatly appreciated.

share|improve this question
add comment

1 Answer

First, to get the properties from the Tiles, you need to loop through them when instantiating the TiledMap. Do not try to do read them during your update block since it's a very slow operation.

Inside your Map Class, add two attributes:

// This will keep a list of Tiles that are blocked
private boolean blocked[][];

// For collision detection, we have a list of Rectangles you can use to test against
private ArrayList<Rectangle> blocks;

Then, inside the Constructor, you can read the Tiles properties:

// This will create an Array with all the Tiles in your map. When set to true, it means that Tile is blocked.
blocked = new boolean[this.getWidth()][this.getHeight()];

// Loop through the Tiles and read their Properties

// Set here the Layer you want to Read. In your case, it'll be layer 1,
// since the objects are on the second layer.
int layer = 1; 

for(int i = 0; i < this.getWidth(); i++) {
    for(int j = 0; j < this.getHeight(); j++) {

        // Read a Tile
        int tileID = getTileId(i, j, layer);

        // Get the value of the Property named "blocked"
        String value = getTileProperty(tileID, "blocked", "false");

        // If the value of the Property is "true"...
        if(value.equals("true")) {

            // We set that index of the TileMap as blocked
            blocked[i][j] = true;

            // And create the collision Rectangle
            blocks.add(new Rectangle((float)i * tileSize, (float)j * tileSize, tileSize, tileSize));
        }
    }
}

The blocked[][] array will store which Tiles are blocked. Use this for further reference, instead of reading the Map Properties again.

About handling the detections:

If you want to check for collisions, just loop through the List of blocks and check if the Player intersects with them.


boolean isInCollision = false;
for(Rectangle ret in yourTiledMap.getBlocks()) {
    if(player.bounds.intersects(ret.bounds)) {
        isInCollision = true;
    }
}
share|improve this answer
    
Thanks, I'll try using that to detect the collisions! The map movement methods are very simple, along the lines of mapX-=Player.velocity;. In the collision handling, it's used as a small buffer to keep the player from getting stuck inside the object's hitbox. –  oracleCreeper Jul 18 '13 at 23:55
    
Additionally, is the tile property reader designed for my own Map class, instead of using a TiledMap in the level state? I noticed that this.getWidth/getHeight would be applied to the level state, when it appears to be referencing the map. –  oracleCreeper Jul 19 '13 at 1:11
    
In my example, the tile property reader is inside a Class that extends Slick's TiledMap. It's just a matter of where your TiledMap object is. –  Lucas Tulio Jul 19 '13 at 2:28
    
Ah, okay. I ended up creating an ExtendedTiledMap class, which seems to work perfectly on a level, although it still doesn't detect the collision on the tile. I'm trying this code for detection if(map.blocked(Player.x,Player.y)){ System.out.println("Collision detected!"); } else{ System.out.println("No collision detected."); } using this to get the result boolean blocked(float x, float y) { return blocked[(int) x/16][(int) y/16]; } –  oracleCreeper Jul 19 '13 at 5:30
    
I updated my answer explaining this. You'll keep using the intersects method, but now you'll test it against the List of Rectangles in the TiledMap. –  Lucas Tulio Jul 19 '13 at 14:15
show 2 more comments

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.