user2875021
user2875021

Reputation: 135

Libgdx tiled map collision detection

I am currently working on a 2d rpg game like final fantasy 1-4. Basically, my tiled map can be loaded and the sprite can walk freely on the map.

How do I handle collisions with tiled map?

I have created three separate tile layers. "Background Layer", "Collision Layer", "Overhead Layer" and I am not sure if this is useful or not..

Edit: I have now created an object layer for collisions with rectangles over the areas I wanted the sprite to collide.

Any help is greatly appreciated. Thank you!

This is my current code

MapObjects collisionObjects = (GameAssets.mainTiledMap).getLayers().get("CollisionLayer").getObjects();
int tileWidth = 16;
int tileHeight = 16;

for (int i = 0; i < collisionObjects.getCount(); i++) {
    RectangleMapObject obj = (RectangleMapObject) collisionObjects.get(i);
    Rectangle rect = obj.getRectangle();

    rect.set(GamePlayer.x, GamePlayer.y, 16,16);

    Rectangle rectobject = obj.getRectangle();
        rectobject.x /= tileWidth;
        rectobject.y /= tileHeight;
        rectobject.width /= tileWidth;
        rectobject.height /= tileHeight;

    if(rect.overlaps(rectobject)) {
        GamePlayer.ableToMove = false;
    }
}

Upvotes: 3

Views: 8052

Answers (3)

Robert P
Robert P

Reputation: 9823

In my game i have a 2D int array walls[][], where i store the information about the Tiles. For me 0 is no wall, so i can go throught. All other numbers repressent some special walltypes, wtih which i have to handle collisions. To detect if a collision happens i do something like this:

if (yMov > 0) {
    int leftX = (int)(position.x - width/2);    // The leftmost point of the Object.
    int rightX = (int)(position.x + width/2);   // The rightmost point of the Object.
    int newMaxY = (int)((position.y * yMov * currentSpeed * delta) + height/2);
    if (walls[leftX][newMaxY] != 0 || walls[rightX][newMaxY] != 0)
         // Collision in positive y-Direction.

Notes:

  1. This is presolve, so detect collision first and then move. For this you have to store the result of the collision detection somewhere.
  2. The Tiles, in which the character is, are defined by the Integer presentation of their position.x and position.y.
  3. yMov describes the percntual value of the movement in y-Direction. So if you go 45° to the right, up you have yMov = 0.5, xMov = 0.5. Left up would be yMov = 0.5, xMov = -0.5.
  4. Use this example code block up there and copy it 3 times, for yMov < 0, xMov > 0, xMov < 0.
  5. The position in this example is the middle of the object. If in your case it is the left lower corner you just need to add full height for up-movement, full width for right-movement and no height/ width for the other movements.

EDIT: I try to explain it better: You have a Sprite defined by his center point:position.x,position.y and his size: size.x, size.y (width and height). Now think about the case, you run to the right. In this case you can never collide with a tile at your left side. Also if you are moving to the right you can not collide with tiles above or under you. So there is only 1 Tile to check: The Tile to your right. Also you can only collide with the Tile to your right, if the right part of your sprite (position.x + size / 2) moves far enought. In case you are moving in between 2 tiles in y direction you have to check the Tile at your newX postition and your upperY (position.y + size.y / 2) and lowerY (position.y - size.y / 2).

To give you a picture of what i am using: Collision detection. Look at the 3rd picture, with this description:

The above image gives us 2 candidate cells (tiles) to check if the objects in those cells collide with Bob.

This collision there is for platformers, where you have a gravity, so you have to check the Tile under you cause of that. In top down games this is not the case. I am not using exactly this method, but the picture shows, what i am doing.

If you have any other questions feel free to ask.

Upvotes: 2

Ferdz
Ferdz

Reputation: 1192

I really don't recommend using rectangles. Instead, what I did in my own game is:

  1. In Tiled, assignate your wall tiles as blocked. To do so, just add a property called block to each individual tile.
  2. In the code, when you process the player movement, write something like this pseudo code:

    try {
        cell = collisionLayer.getCell((int) (x / collisionLayer.getTileWidth()), (int) (y / collisionLayer.getTileHeight()));
    } catch (Exception e) {
        e.printStackTrace();
    }
    
        if (cell.getTile().getProperties().containsKey("blocked")) {
        blocked = true;
        }
    

where x and y are the position of the cell you want to check. And then if blocked = true, do not move the player. If blocked = false, move the player.

I might have been unclear in this answer, if I was, please don't hesitate to send me a message or check this awesome tutorial by dermetfan.

Upvotes: 2

Flipurbit
Flipurbit

Reputation: 1

I am assuming that you have a method that handles the movement phase, if so the way that I have done it in the past is that after the movement direction is registered run a check against your rectangular collision layer, if the position is to cross over one of the boundaries then return back/run a method for however you want to handle it ie player dies, or players position does not change.

Upvotes: 0

Related Questions