2
\$\begingroup\$

I'm using a tiled tmx map, and I created a class that adds bodies to each tile within a certain layer. This has been working great so far except for when a character or an enemy moves around on the screen, its body gets stuck on an edge between two tiles.

This seems to happen "sometimes" and in certain spots. Jumping makes you unstuck but it's annoying when it happens, and I tried increasing the position iterations, but the problem keeps reoccurring.

Here's what my game looks like:

enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ Can you show a state where it is blocked? Can you also include how is "connection" between body and its sprite handled? \$\endgroup\$
    – wondra
    Commented Sep 17, 2014 at 17:01

3 Answers 3

1
\$\begingroup\$

The way Box2D resolves collisions results in it working very poorly with tiles maps where the tiles are converted into square bodies. It is best to have a separate layer for specifying objects to use for collision which is completely separate from the graphical information for the tile map. You can then use this object layer to generate the Box2D bodies needed for your game.

Creating an Object Layer for Specifying the Collision Layer.

Excerpt from a gamedevelopment.tutsplus.com Tutorial

Now if we wanted to specify collisions there are a few ways we can do that too. I'm going to use an object layer since they can be used for just about anything, so it will be a nice introduction.

Select Layer > Add Object Layer. With the object layer selected, select the "Insert Object" at the top of the menu. Now you can click and drag a box around the trunk of the tree to define the collision box.

enter image description here

Converting that Object Layer to Box2D Bodies

This is a solved problem. See this question for an implementation using the same technologies you are.

\$\endgroup\$
3
  • \$\begingroup\$ Im actually from that solution lol. I didn't think it was efficient because id have to manually set each objects collision shape and the ground and area where my feet were became inconsistent because im manually drawing the shapes \$\endgroup\$
    – HighMrSai
    Commented Sep 17, 2014 at 19:46
  • \$\begingroup\$ I use this method frequently. Using the polygon tool to create the collision surfaces is very simple and quite quick. The impact to your amount of time it will take to create new levels will be very minimal. The alternative is to make something like a fill algorithm that merges the boxes together. Altering the behavior for Box2d to allow sliding/rolling smoothly across the a surface composed of squares is a task I have not seen anyone perform successfully. \$\endgroup\$ Commented Sep 17, 2014 at 19:59
  • \$\begingroup\$ I use this method also. You can activate snap to grid in your object layer. Like this you can first place all your polygons on the grid and you don't have to care so much for small differences. \$\endgroup\$ Commented Sep 18, 2014 at 15:07
1
\$\begingroup\$

Change your actor body so the lower part is an arc. Like this it should be able to get over small steps and or walking up/down diagonal slopes.

Example Body

\$\endgroup\$
1
\$\begingroup\$

I ended up redoing to algorithm for building the map. This seems to be working really really well

enter image description here

I wrote this to build it, this basically makes a body for each tile, if there are tiles next to each other, horizontally, it will group them together and create a single body for those tiles

 private static void buildCollision(Map map, World world){
        TiledMapTileLayer layer = (TiledMapTileLayer) map.getLayers().get("collisionlayer");
        BodyDef bDef = new BodyDef();
        PolygonShape shape = new PolygonShape();
        FixtureDef fDef = new FixtureDef();
        fDef.density = 2.5f;
        fDef.isSensor = false;
        fDef.friction = 0;
        fDef.restitution = 0;

        bDef.type = BodyType.StaticBody;
        Body tileBody = world.createBody(bDef);
        tileBody.setUserData("ground");
        int cellcounter = 0;
        TiledMapTileLayer.Cell cell, nextCell, prevCell;
        int firstCellIndexX = 0, firstCellIndexY = 0;

        for(int j = 0; j < layer.getHeight(); j++){
            for(int i = 0; i < layer.getWidth(); i++){
                cell = layer.getCell(i, j);
                prevCell = layer.getCell(i-1, j);
                nextCell = layer.getCell(i+1, j);

                if(cell != null){
                    cellcounter++;



                    if(prevCell == null){
                        firstCellIndexX = i;
                        firstCellIndexY = j;
                    }

                    if(nextCell == null){
                        float width = layer.getTileWidth() * cellcounter * scaledRatio;
                        float height = layer.getTileHeight() * scaledRatio;

                        shape.setAsBox(width/2, height/2, new Vector2((firstCellIndexX * layer.getTileWidth() * scaledRatio) + (width/2), (firstCellIndexY * layer.getTileHeight() * scaledRatio) + (height/2)), 0);
                        fDef.shape = shape;
                        tileBody.createFixture(fDef);
                        cellcounter = 0;
                    }
                }
            }
        }
        shape.dispose();

    }
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .