0

I am creating a brick breaker game using libgdx, using the TiledMapEditor to create my levels. i have a layer for my brick graphics and a layer for my brick objects. i have collision working with my brick objects, i have the tile in the brick graphics layer set to null when Collison happens and working. Great, Awesome... except i have created my brinks to be multiple tiles in size. so when i collide with my brick object it turns collision off and removes that specific cell graphic. Leaving me with half the brick still showing on the screen. i have checked the documentation on tiledMaps, the libdx dox and searched slack/goodle/youtube/tiled dox. i thought of creating a method to check if the cells around is not null then to turn them null, but that wont work when i have bricks right beside each other. any ideas or suggestions or even a hint to where to look would be much appreciated. Or to change my sizing of my bricks to fit in one tile. i would rather figure a way out to remove all cells that are over the specified objects

Class for creating my interactive objects

    public InteractiveTileObject(World world, TiledMap map, Rectangle rect) {
        this.world = world;
        this.map = map;
        this.rect = rect;

        bDef = new BodyDef();
        fDef = new FixtureDef();
        shape = new PolygonShape();

        bDef.type = BodyDef.BodyType.StaticBody;
        bDef.position.set((rect.getX() * Arma.VSCALE) + (rect.getWidth() * Arma.VSCALE / 2),
                (rect.getY() * Arma.VSCALE) + (rect.getHeight() * Arma.VSCALE / 2));

        body = world.createBody(bDef);

        shape.setAsBox(rect.getWidth() * Arma.VSCALE / 2, rect.getHeight() * Arma.VSCALE / 2);
        fDef.shape = shape;
        fixture = body.createFixture(fDef);
    }

    public abstract void onHit();

    public void setCategoryFilter(short filterBit){
        Filter filter = new Filter();
        filter.categoryBits = filterBit;
        fixture.setFilterData(filter);
    }
    public TiledMapTileLayer.Cell getCell(){
        int column = (int)(body.getPosition().x / Arma.VSCALE / 50);
        int row = (int)(body.getPosition().y / Arma.VSCALE / 50);
        TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(2);
        return layer.getCell(column,row);
    }
}

Class that pulls objects from TiledMapEditor

public B2WorldCreator(PlayScreen screen) {
        World world = screen.getWorld();
        TiledMap map = screen.getMap();


        BodyDef bDef = new BodyDef();
        PolygonShape shape = new PolygonShape();
        FixtureDef fDef = new FixtureDef();
        Body body;

        //create boundy body/fix
        for (MapObject object : map.getLayers().get(3).getObjects().getByType(RectangleMapObject.class)) {
            Rectangle rect = ((RectangleMapObject) object).getRectangle();
            new Boundary(world, map, rect);
        }
        //create bricks body/fix
        for (MapObject object : map.getLayers().get(4).getObjects().getByType(RectangleMapObject.class)) {
            Rectangle rect = ((RectangleMapObject) object).getRectangle();
            new Brick(world, map, rect);
        }

        //create wall light body/fix
        for (MapObject object : map.getLayers().get(5).getObjects().getByType(RectangleMapObject.class)) {
            Rectangle rect = ((RectangleMapObject) object).getRectangle();
            new Wall(world, map, rect);
        }
    }
}

Brick Class

public class Brick extends InteractiveTileObject{

    public Brick(World world, TiledMap map, Rectangle bounds) {
        super(world, map, bounds);
        fixture.setUserData(this);
        setCategoryFilter(Arma.BRICK_BIT);
    }

    @Override
    public void onHit() {
        Gdx.app.log("Brick", "Collision");
        setCategoryFilter(Arma.DEYSTROYED_BIT);
        getCell().setTile(null);

    }
}

i created this method which works but still need to enter the size of the objects, i would much rather get your method working Tobias.

public void getCells(int width, int height){
        int column = (int)((body.getPosition().x / Arma.VSCALE -25) / 50);
        int row = (int)((body.getPosition().y / Arma.VSCALE -25) / 50 );
        TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(2);
        for (int i = 0; i < width; i++){
            for (int k = 0; k < height; k++){
                if (layer.getCell(column + i, row + k) != null)
                    layer.getCell(column + i, row + k).setTile(null);
            }
        }
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Poehnell
  • 27
  • 4

1 Answers1

0

You are selecting the cells, that you want to remove by their position on the tiled map. You can do the same for the other cells, that are in the range of the Box2D body, that was hit. The only difference is, that it's a bit more difficult to check whether the tested position is still inside the body (currently you are only checking the body's position).

A solution could look like this:

public class InteractiveTileObject {

    // ... other methods

    public Array<TiledMapTileLayer.Cell> getCells(){
        Array<TiledMapTileLayer.Cell> cells = new Array<>();
        TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get(2);
        
        for (int i = 0; i < MAX_NUMBER_OF_CELLS_PER_BODY; i++) {
            for (int j = 0; j < MAX_NUMBER_OF_CELLS_PER_BODY; j++) {
                float x = body.getPosition().x + i * SIZE_OF_A_TILE_CELL;
                float y = body.getPosition().y + j * SIZE_OF_A_TILE_CELL;
                if (doesBodyContainPoint(body, x, y)) {
                    int column = (int)(x / Arma.VSCALE / 50);
                    int row = (int)(y / Arma.VSCALE / 50);
                    cells.add(layer.getCell(column, row));
                }
            }
        }
        
        return cells;
    }

    private boolean doesBodyContainPoint(Body body, float x, float y) {
        // to check whether the body contains a point you need to check whether any of the body's fixtures contains the point:
        for (Fixture fixture : body.getFixtureList()) {
            if (fixture.testPoint(new Vector2(x, y)) {
                return true;
            }
        }
        return false;
    }
}

After you filled in the constants of MAX_NUMBER_OF_CELLS_PER_BODY and SIZE_OF_A_TILE_CELL you should be able to find every cell, this body contains. Then you can just remove them like you did before.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
Tobias
  • 2,547
  • 3
  • 14
  • 29
  • Sweet well this is defiantly looking like we are heading in the right direction. i implemented that code. tile size is 50X50 and my brick are 100x by 50y. so when i run this code with a MAX_NUMBER_OF_CELLS_PER_BODY = 2 and the SIZE_OF_A_TILE = 50. i used a for loop to pass through the Cells Array and set each cell to null in the ARRAY. i am still receiving the same effect. when i print to screen the size of the array it is always 1 no matter max number of cells per body count i adjust. – Poehnell Jan 18 '21 at 21:17
  • im wondering if because the origin of a body is in the center vs the origin on the shape is bottom left. i was experimenting and instead of using the body using the shape, i found that depending on where i started drawing the object in TILED_MAP_EDITOR was the point of origin on the object. – Poehnell Jan 18 '21 at 21:24
  • I was expecting the position of the body whould be the bottom left. If it's the point where you started drawing instead, you also need to search in negative x and y direction, by changing the for loops to `for (int i = -MAX_NUMBER_OF_CELLS_PER_BODY; i < MAX_NUMBER_OF_CELLS_PER_BODY; i++)` (same for the next loop). If this also doesn't fix the problem you should try to debug it, to see why there is only one Cell found (see [this post](https://stackoverflow.com/questions/25385173/what-is-a-debugger-and-how-can-it-help-me-diagnose-problems) for help on debugging) – Tobias Jan 19 '21 at 05:38