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:
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
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.