2
votes

I am currently using box2d physics engine in java in libgx, and i am facing problems with collisions. The problem is that the body stops moving, and a collision point appears while on a flat area. The way im working is i am making multiple bodies, each representing a block, and those blocks are side-by-side. Look at the collision point here:

enter image description here

the body should not collide here for the Y coordinate of the bodies is equal, and their side is equal as well.

float PPM = 100;
float side = 45;
     for (float i = start; i < end; i++) {
        /**
         * perlin noise for terrain
         */
        def.type = BodyDef.BodyType.StaticBody;
        float place = Maths.map(noise.noise(off, off), 0, 1, -10, 50);
        if (place < 10) {
            place = 0;
        } else if (place < 20) {
            place = side;
        } else if (place < 30) {
            place = side * 2;
        } else if (place < 40) {
            place = side * 3;
        } else if (place <= 50) {
            place =  side * 4;
        }


        place += side / 2;

        float posx = (i * side);
        float posy = place;
        float size = side / 2f;
        def.position.set(posx / PPM, posy / PPM);
        b = world.createBody(def);
        shape.setAsBox(size / PPM, size / PPM);
        fdef.shape = shape;
        fdef.isSensor = false;
        b.createFixture(fdef);
        off += 0.01;
        toSetLast = posx + side;

        GrassBlock grass = new GrassBlock(b, new 
        Vector2(b.getPosition().x * PPM, b.getPosition().y * PPM));
        //dirt under grass
        for (float j = (place / side) - 1; j >= -1; j--) {
            posy = j * side;

            def.position.set(posx / PPM, posy / PPM);
            b = world.createBody(def);
            shape.setAsBox(size / PPM, size / PPM);
            fdef.isSensor = false;
            fdef.shape = shape;
            b.createFixture(fdef);
            DirtBlock dirt = new DirtBlock(b, new 
            Vector2(b.getPosition().x * PPM, b.getPosition().y * PPM));
            addBlock(dirt.getLocation(), dirt);
        }
        addBlock(grass.getLocation(), grass);

    }
2

2 Answers

2
votes

I believe what you're experiencing is a known short-coming of the Box2D library.

See What could cause a sudden stop in Box2D? for another write-up of this problem. See Box2D C++ tutorials - Ghost vertices for an explanation of what's going on and what you can do to mitigate the problem...

Basically, use a chain-shape for the ground like texture instead of polygons (or over the polygons) so your moving block actually moves on top of the chain. That assumes the version of the java box2d implementation you're using has the chain shape in it that provides "ghost vertices" support.

Under the hood details...

While from the user's perspective chain shapes provide smoothing, under the hood, it's edge shapes that get used to do the smoothing. Edge shapes do this with two special extra vertices (in addition to the expected two of an edge). When the library is evaluating a contact between a chain shape and a polygon (or a circle), it does that by identifying the segment of the chain that the contact could be occurring with. It then translates that chain segment into an edge with its extra vertices set to the adjacent vertices in the chain. And then the contact is evaluated between that translated edge and the polygon (or circle). This occurs automatically with chain shapes and there's no option in chain shapes that is used to gain this behavior.

A user could achieve the same results as achieved with chain shapes by stitching together edge shapes for all the segments of the chain and setting all of the edges' extra vertices to the logically adjacent vertices. That uses significantly more memory than the chain shape however and requires the user to write more code to do (at least for chains having more than two vertices).

2
votes

Although Louis Langholtz's answer is already good, I have more to add.

Chain or Ghost vertices are generally recommended approaches but :-

  • It is hard to use in practice.
  • It requires coder to manually joint those edges/corners together.
    (tedious in some scenario)

I recommend beveling the box instead :-

enter image description here

I have tested (jbox2d) - it can reduce the effect from the glitch significantly.
The disadvantage of this approach is that it demands additional vertices.
(e.g. 4 vertices -> 8 vertices )

Thus, it demands more computational power.

Therefore, in practices, I generally divide all bodies into 2 groups :-

  • OK to have glitch (e.g. debris) -> don't modify (cheap)
  • Can't have glitch (e.g. character) -> use beveling approach (more expensive)

Personally, I hope there is an easy way to use chain/ghost as Louis Langholtz recommend, though.