Search code examples
androidlibgdxbox2djbox2d

Box2d creates specific body and fixture seemingly at random


I have created an android application similar to Not Tetris 2 using Libgdx with Box2d.

It can successfully remove a slice from the world, which obviously involves duplicating several bodies and destroying/creating fixtures. However, seemingly at random, a body with a 2x2 fixture will appear. The body and fixture are displayed using information related to the objects around it when it is created, so I narrowed its creation down to the following function:

Body duplicateBody(Body original){
    BodyDef d = new BodyDef();
    d.position.set(original.getPosition());
    d.angle = original.getAngle();
    d.linearVelocity.set(original.getLinearVelocity());
    d.angularVelocity = original.getAngularVelocity();

    Body dup = world.createBody(d);
    dup.setType(BodyDef.BodyType.DynamicBody);

    return dup;
}

I use this function in 2 different contexts:

  1. Making a copy of the body if a "slice" cuts one in two -- I then transfer the fixtures which are below to it.
  2. When a fixture is below the line then it is added to a body created for ones below
  3. Making a copy of the body when groups of fixtures are separated

I commented out the code responsible for the third instance and still had the 2x2 boxes spawning, so here are the functions relevant to the others:

...
if (below && !above) {
    //copy fixture, add copy to lower body and remove original
    Body top = fixture.getBody();
    FixtureDef n = new FixtureDef();
    PolygonShape s = new PolygonShape();
    s.set(getLocalVerticesOfFixture(fixture));
    n.shape = s;
    n.density = fixture.getDensity();
    //create lower body if a lower one doesn't already exist
    if (!topBottomPairs.containsKey(top)) {
        Body dup = duplicateBody(top);
        topBottomPairs.put(top, dup);
    }
    //delete fixture
    remove.add(fixture);
    Fixture f = topBottomPairs.get(top).createFixture(n);
    s.dispose();
}
...
if (below && above) {
    //copy fixture, add copy to lower body, but keep original on upper as it needs to split
    FixtureDef n = new FixtureDef();
    PolygonShape s = new PolygonShape();
    s.set(getLocalVerticesOfFixture(fixture));
    n.shape = s;
    n.density = fixture.getDensity();

    Body top = fixture.getBody();
    //create lower body if a lower one doesn't already exist
    if (!topBottomPairs.containsKey(top)) {
        Body dup = duplicateBody(top);
        topBottomPairs.put(top, dup);
    }
    Fixture second = topBottomPairs.get(top).createFixture(n);
    s.dispose();
}

....

private Vector2[] getLocalVerticesOfFixture(Fixture fixture) {
    PolygonShape shape = ((PolygonShape) fixture.getShape());
    Vector2[] localVertices = new Vector2[shape.getVertexCount()];
    for (int i = 0; i < shape.getVertexCount(); i++) {
        localVertices[i] = new Vector2();
        shape.getVertex(i, localVertices[i]);
    }
    return localVertices;
}

I also have this remove fixture function which runs on all fixtures I want to remove:

private void smartDeleteFixture(Fixture f){
    f.getBody().destroyFixture(f);
    if(f.getBody().getFixtureList().size == 0){
        world.destroyBody(f.getBody());
    }
}

Nowhere do I create vertices, let alone a fixture of a 2x2 shape. I was wondering if this duplication function has any flaws, or if I stumbled upon some "default shape" that box2d uses.

Edit: I have removed anything not related to the manipulation of box2d bodies. Hope that helps


Solution

  • Deleted this question as I decided to perform a major recode and hoped that would fix my problem. It did not, but I figured out the cause.

    I looked through box2d and found a couple instances of code similar to this in the polygon shape class:

    if (n < 3)
    {
        // Polygon is degenerate.
        b2Assert(false);
        SetAsBox(1.0f, 1.0f);
        return;
    }
    

    These instances check the number of vertices after various operations and turn the shape into a 2x2 box if there are fewer than 3. One of these operations makes the shape convex. Another checks if vertices are close together (closer than 0.0025f), deleting one if so.

    In my case, the problem was simple. Some of my vertices were less than 0.0025f from each other, resulting in them being deleted, the vert count dropping below 3, an assertion being ignored, and then my shape being turned into a 2x2 box. I hope this helps someone out.