Search code examples
javalibgdxcollision-detectiontiled

LibGDX Tiled get object property on collision


I'm working on a game in LibGDX, and have a map set up with Tiled. I added a custom String property to objects in a specific layer to get further information, what object it represents.

I have a ContactListener set up, that calls a method in the abstract class of the map object. The listener looks like this:

@Override
public void beginContact(Contact contact) {

    Fixture fixtureA = contact.getFixtureA();
    Fixture fixtureB = contact.getFixtureB();

    if (fixtureA.getUserData() == "player" || fixtureB.getUserData() == "player") {
        // Get either fixture A or B, depending on which of them is the player fixture
        Fixture player = fixtureA.getUserData() == "player" ? fixtureA : fixtureB;
        // Get the colliding object, depending on which of them is the player fixture
        Fixture collidedObject = player == fixtureA ? fixtureB : fixtureA;

        // Determine what kind of object the player collided with and trigger the respectable method
        if (collidedObject.getUserData() instanceof InteractiveMapTileObject) {
            ((InteractiveMapTileObject) collidedObject.getUserData()).onPlayerBeginContact();
        } else if (collidedObject.getUserData() instanceof Enemy) {
            ((Enemy) collidedObject.getUserData()).onPlayerBeginContact();
        }
    }
}

When the player hits an object of an instance of InteractiveMapTileObject, the onPlayerBeginContact() method gets called, which looks like this:

@Override
public void onPlayerBeginContact() {
    MapObjects objects = playScreen.getMap().getLayers().get("weapon").getObjects();
    for (MapObject object : objects) {
        if (object.getProperties().containsKey("weapon_name")) {
            String weaponName = object.getProperties().get("weapon_name", String.class);
            Gdx.app.log("Picked up weapon", weaponName);
        }
    }
}

Here, I am getting the objects of the "weapon" layer in the map, and then iterate through it to find the correct property and it's value. This works fine as it is.

The problem now is, that I obviously have multiple objects in the layer, and therefore multiple MapObjects. I need a way to identify the object, that the player collided with and then get it's property.

Is it possible to do that with the ContactListener, or do I need to implement something else? I already searched through a ton of posts, but didn't get lucky.


Solution

  • I solved my problem by writing a custom method in my abstract class to check for an intersection of each object in a specific object layer.

    protected MapObject getCellProperties(int layerIndex) {
        MapObjects mapObjects = map.getLayers().get(layerIndex).getObjects();
    
        for (MapObject mapObject : mapObjects) {
            MapProperties mapProperties = mapObject.getProperties();
    
            float width, height, x, y;
            Rectangle objectRectangle = new Rectangle();
            Rectangle playerRectangle = new Rectangle();
    
            if (mapProperties.containsKey("width") && mapProperties.containsKey("height") && mapProperties.containsKey("x") && mapProperties.containsKey("y")) {
                width = (float) mapProperties.get("width");
                height = (float) mapProperties.get("height");
                x = (float) mapProperties.get("x");
                y = (float) mapProperties.get("y");
                objectRectangle.set(x, y, width, height);
            }
    
            playerRectangle.set(
                    playScreen.getPlayer().getX() * MainGameClass.PPM,
                    playScreen.getPlayer().getY() * MainGameClass.PPM,
                    playScreen.getPlayer().getWidth() * MainGameClass.PPM,
                    playScreen.getPlayer().getHeight() * MainGameClass.PPM
            );
    
            // If the player rectangle and the object rectangle is colliding, return the object
            if (Intersector.overlaps(objectRectangle, playerRectangle)) {
                return mapObject;
            }
        }
    
        // If no colliding object was found in that layer
        return null;
    }
    

    This is probably not the best solution, but it works wonderfully.