Was bewirkt, dass sich Box2D-Drehgelenke trennen?

7

Ich habe eine Stoffpuppe aus dynamischen Körpern (Rechtecken) und einfachen Drehgelenken (mit unteren und oberen Winkeln) erstellt. Wenn meine Stoffpuppe auf den Boden trifft (was ein statischer Körper ist), scheinen die Körper zu zappeln und die Gelenke trennen sich.

Es sieht so aus, als ob die Körper am Boden kleben und der Schwung der Stoffpuppe das Gelenk auseinander zieht (siehe Abbildung unten).

Alt-Text

Ich bin nicht sicher, ob es verwandt ist, aber ich verwende den Badlogic GDX Java-Wrapper für Box2D. Hier sind einige Ausschnitte aus dem meiner Meinung nach relevantesten Code:

private RevoluteJoint joinBodyParts(
    Body a, Body b, Vector2 anchor, 
    float lowerAngle, float upperAngle) {

    RevoluteJointDef jointDef = new RevoluteJointDef();

    jointDef.initialize(a, b, a.getWorldPoint(anchor));

    jointDef.enableLimit = true;
    jointDef.lowerAngle = lowerAngle;
    jointDef.upperAngle = upperAngle;

    return (RevoluteJoint)world.createJoint(jointDef);
}

private Body createRectangleBodyPart(
    float x, float y, float width, float height) {

    PolygonShape shape = new PolygonShape();
    shape.setAsBox(width, height);

    BodyDef bodyDef = new BodyDef();
    bodyDef.type = BodyType.DynamicBody;
    bodyDef.position.y = y;
    bodyDef.position.x = x;

    Body body = world.createBody(bodyDef);

    FixtureDef fixtureDef = new FixtureDef();
    fixtureDef.shape = shape;
    fixtureDef.density = 10;

    fixtureDef.filter.groupIndex = -1;
    fixtureDef.filter.categoryBits = FILTER_BOY;
    fixtureDef.filter.maskBits = FILTER_STUFF | FILTER_WALL;

    body.createFixture(fixtureDef);
    shape.dispose();

    return body;
}

Ich habe die Methode zum Erstellen des Kopfes übersprungen, da sie der Rechteckmethode ziemlich ähnlich ist (nur mit einer Krikelform).

Diese Methoden werden wie folgt verwendet:

    torso = createRectangleBodyPart(x, y + 5, 0.25f, 1.5f);
    Body head = createRoundBodyPart(x, y + 7.4f, 1);

    Body leftLegTop = createRectangleBodyPart(x, y + 2.7f, 0.25f, 1);
    Body rightLegTop = createRectangleBodyPart(x, y + 2.7f, 0.25f, 1);
    Body leftLegBottom = createRectangleBodyPart(x, y + 1, 0.25f, 1);
    Body rightLegBottom = createRectangleBodyPart(x, y + 1, 0.25f, 1);

    Body leftArm = createRectangleBodyPart(x, y + 5, 0.25f, 1.2f);
    Body rightArm = createRectangleBodyPart(x, y + 5, 0.25f, 1.2f);

    joinBodyParts(torso, head, new Vector2(0, 1.6f), headAngle);

    leftLegTopJoint = joinBodyParts(torso, leftLegTop, new Vector2(0, -1.2f), 0.1f, legAngle);
    rightLegTopJoint = joinBodyParts(torso, rightLegTop, new Vector2(0, -1.2f), 0.1f, legAngle);
    leftLegBottomJoint = joinBodyParts(leftLegTop, leftLegBottom, new Vector2(0, -1), -legAngle * 1.5f, 0);
    rightLegBottomJoint = joinBodyParts(rightLegTop, rightLegBottom, new Vector2(0, -1), -legAngle * 1.5f, 0);

    leftArmJoint = joinBodyParts(torso, leftArm, new Vector2(0, 1), -armAngle * 0.7f, armAngle);
    rightArmJoint = joinBodyParts(torso, rightArm, new Vector2(0, 1), -armAngle * 0.7f, armAngle);
Nick Bolton
quelle
Führen Sie Ihre Physiksimulation mit einem festen Zeitschritt durch? Wenn nicht, sollten Sie das auf jeden Fall zuerst tun.
Bummzack

Antworten:

5

Box2D verwendet einen iterativen und keinen geschlossenen Löser. Dies bedeutet, dass alle Einschränkungen etwas weich sind. Box2D wird sich sehr bemühen, das zu tun, was Sie sagen, aber es treten Ungenauigkeiten auf.

Um dies zu minimieren, können Sie verschiedene Dinge in der Reihenfolge ihrer Wichtigkeit tun:

  • Verwenden Sie Zeitschritte mit fester Größe (das erste Argument dafür Step). Dies macht den Solver stabiler - Ihre Ungenauigkeiten heben sich mit größerer Wahrscheinlichkeit gegenseitig auf oder verhalten sich jedes Mal zumindest gleich.
  • Verwenden Sie einen kleineren Zeitschritt (1/60 oder 1/120 anstelle von 1/30). Kleinere Zeitschritte bedeuten kleinere Ungenauigkeiten.
  • Verwenden Sie mehr Solver-Iterationen (das 2./3. Argument dazu Step). Sie sollten versuchen, mindestens 10 von jedem zu bekommen. Mehr Solver-Iterationen bedeuten mehr Chancen bei jedem Zeitschritt, Stabilität zu finden und Einschränkungen korrekt zu erfüllen - ungefähr weniger Ungenauigkeiten. Ein kleinerer, stabilerer Zeitschritt ist jedoch besser als mehr Iterationen. Bei ausreichend komplizierten Einschränkungen können Sie diese möglicherweise nie zu 100% korrekt lösen. Reduzieren Sie daher den Zeitschritt, bevor Sie die Iterationen erhöhen.
  • Verwenden Sie weniger dichte Formen. Dichte 10 ist ziemlich schwer. Versuchen Sie, etwas Kleineres wie 1 als Standarddichte zu standardisieren.

quelle
Hallo Joe, danke für den Rat. Ich habe alle Ihre Vorschläge ausprobiert, aber leider schien dies keinen Unterschied zu machen. Hier ist der vollständige Quellcode (es ist momentan nur ein hackiger Prototyp) - pastebin.com/F6YX3AyV
Nick Bolton