Essa Rebaño
Essa Rebaño

Reputation: 103

Libgdx: Tiled Objects layer for collision

Good day sirs,

I'm trying to figure out now is how to perform a collision detection for my player by using a Tiled Object layer, to be more specific I wanted it to detect a polyline which I have draw in my tiled map. As I was researching in google about collision detection for Tiled, I found this simple example superkoala sample for TiledmapLayer. In my understanding of the code (correct me if I'm wrong), It order to detect a collision the player will read each tile of a certain layer for example a foreground layer which contains the ground and other objects.

Basically, What I did with my Object layer is I named my polyline to Wall and for the type I put in numbers depending on how many polylines I have used. So that for future use I could call this wall numbers for my collision.

Can anyone give me a sample code about reading objects and using them for collision detection?or just a simple tip or Idea on how I could solve this?any help would be appreciated.

Upvotes: 3

Views: 3489

Answers (2)

Lifeweaver
Lifeweaver

Reputation: 1042

I came across this question/answer and wanted to share what I used, I've not figured everything out exactly yet, but it has been working for me:

    void buildMap() {
        MapLayer collisionLayer = (MapLayer) map.layers.find { it.name == 'collision' }
        collisionLayer.objects.each { MapObject mapObject ->
            Body body = null

            if(mapObject instanceof RectangleMapObject) {
                Rectangle rectangle = adjustRectangleDimensions(mapObject.rectangle)
                body = bodyFactory.makeBoxPolyBody(
                        rectangle.x,
                        rectangle.y,
                        rectangle.width,
                        rectangle.height,
                        BodyFactory.STONE,
                        BodyDef.BodyType.StaticBody
                )
            }

            if(mapObject instanceof PolygonMapObject) {
                Polygon polygon = adjustPolygonDimensions(mapObject.polygon)
                body = bodyFactory.makePolygonShapeBody(
                        polygon.vertices,
                        polygon.x,
                        polygon.y,
                        BodyFactory.STONE,
                        BodyDef.BodyType.StaticBody
                )
            }


            body.fixtureList.first().filterData.categoryBits = GROUND_BIT
            body.fixtureList.first().filterData.maskBits = PLAYER_BIT // can combine with | if multiple i.e. GROUND_BIT | PLAYER_BIT
        }
    }

    static Rectangle adjustRectangleDimensions(Rectangle rectangle) {
        rectangle.x = rectangle.x * RenderingSystem.PIXELS_TO_METRES * 2 as float
        rectangle.y = rectangle.y * RenderingSystem.PIXELS_TO_METRES * 2 as float
        rectangle.width = rectangle.width * RenderingSystem.PIXELS_TO_METRES * 2 as float
        rectangle.height = rectangle.height * RenderingSystem.PIXELS_TO_METRES * 2 as float
        return rectangle
    }

    static Polygon adjustPolygonDimensions(Polygon polygon) {
        float x = polygon.x * RenderingSystem.PIXELS_TO_METRES as float
        float y = polygon.y * RenderingSystem.PIXELS_TO_METRES as float
        polygon.setPosition(x, y)

        float[] vertices = polygon.vertices //might need to get transformedVertices at some point, seems to work now
        def adjustedVertices = []
        vertices.each {
            adjustedVertices.add(it * RenderingSystem.PIXELS_TO_METRES as float)
        }

        polygon.vertices = adjustedVertices

        return polygon
    }

In this case RenderingSystem.PIXELS_TO_METRES was the unitscale I used for my OrthogonalTiledMapRenderer.

The bodyFactory I used can be found https://github.com/lifeweaver/learningGames/blob/master/core/src/net/stardecimal/game/BodyFactory.groovy

Also see https://github.com/yichen0831/Pacman_libGdx/blob/master/core/src/com/ychstudio/builders/WorldBuilder.java for another example.

Upvotes: 0

Ferdz
Ferdz

Reputation: 1192

What i recommend on doing in your case is not to use object layers but properties for the specific tiles. Let's say you have one tile in 'Tiled' and you are sure to only use it as a wall. Click on that specific tile and add the property "blocked". Then, in your code, you can check every cell next to the player and if it contains the property "blocked", not allow the player to go in that direction. Here is a pseudo-code on how I did it:

private boolean isCellBlocked(float x, float y) {
    Cell cell = null;
    boolean blocked = false;

    try {
        cell = collisionLayer.getCell((int) (x / collisionLayer.getTileWidth()), (int) (y / collisionLayer.getTileHeight()));
    } catch (Exception e) {
        e.printStackTrace();
    }

    if (cell != null && cell.getTile() != null) {
        if (cell.getTile().getProperties().containsKey("blocked")) {
            blocked = true;
        }
    }
    return blocked;
}

and you can make the player call isCellBlocked(x, y) every time he updates.

I also did a collidesSide(float x, float y) for every side (collidesTop(float x, float y), etc).

I hope this helps you out, even if it doesn't use the system you wanted to. For any more help on this, I'm heavily using libGDX for my collision detection on a big project, so don't hesitate to contact me!

Upvotes: 2

Related Questions