使用Box2d,如何创建像Parachute Ninja (ZeptoLab)这样的橡胶线(橡皮筋/ flex 绳)?

-(void) CreateElasticRope {
//=======Params
// Position and size
b2Vec2 lastPos = b2Vec2(4,4); //set position first body
float widthBody = 0.35;
float heightBody = 0.1;
// Body params
float density = 0.05;
float restitution = 0.5;
float friction = 0.5;
// Distance joint
float dampingRatio = 0.85;
float frequencyHz = 10;
// Rope joint
float kMaxWidth = 1.1;
// Bodies
int countBodyInChain = 10;
b2Body* prevBody;
//========Create bodies and joints
for (int k = 0; k < countBodyInChain; k++) {
    b2BodyDef bodyDef;
    if(k==0 || k==countBodyInChain-1) bodyDef.type = b2_staticBody; //first and last bodies are static
    else bodyDef.type = b2_dynamicBody;
    bodyDef.position = lastPos;
    lastPos += b2Vec2(2*widthBody, 0); //modify b2Vect for next body
    bodyDef.fixedRotation = YES;
    b2Body* body = world->CreateBody(&bodyDef);

    b2PolygonShape distBodyBox;
    distBodyBox.SetAsBox(widthBody, heightBody);
    b2FixtureDef fixDef;
    fixDef.density = density;
    fixDef.restitution = restitution;
    fixDef.friction = friction;
    fixDef.shape = &distBodyBox;
    body->CreateFixture(&fixDef);

    if(k>0) {
        //Create distance joint
        b2DistanceJointDef distJDef;
        b2Vec2 anchor1 = prevBody->GetWorldCenter();
        b2Vec2 anchor2 = body->GetWorldCenter();
        distJDef.Initialize(prevBody, body, anchor1, anchor2);
        distJDef.collideConnected = false;
        distJDef.dampingRatio = dampingRatio;
        distJDef.frequencyHz = frequencyHz;
        world->CreateJoint(&distJDef);

        //Create rope joint
        b2RopeJointDef rDef;
        rDef.maxLength = (body->GetPosition() - prevBody->GetPosition()).Length() * kMaxWidth;
        rDef.localAnchorA = rDef.localAnchorB = b2Vec2_zero;
        rDef.bodyA = prevBody;
        rDef.bodyB = body;
        world->CreateJoint(&rDef);

    } //if k>0

    prevBody = body;
} //for -loop
}

我使用距离和绳接头,设置不同的参数阻尼值和频率Hz值,但效果远非示例(我的线程很长一段时间都恢复到原始状态,并且没有那么 flex )。

最佳答案

您可以通过施加力来模拟 Spring 。在每个时间步长上更新连接的物体上的力(必要时也要唤醒物体)。如果其中一个物体是地面(或静态物体),则无需仅对动态物体施加任何力。

常规 Spring 会根据挠度施加拉力和压力(拉力和推力)。在您的情况下,您有一个蹦极,因此仅靠拉力(拉力)就不会产生压力。

这是您需要的公式:

F = K * x

其中F是力,K是 Spring 刚度(力/挠度),x是挠度。挠度计算为初始长度和当前长度(连接点之间的距离)之差。 F的符号确定它是在拉动还是 push 。一旦计算出F,就需要沿着连接两个 Spring 连接点的直线应用它。为了达到力平衡,您需要在相反的方向上施加此力(其中一个物体为正,另一个物体为负)。这是因为牛顿爵士是这样说的。

这是一个示例(可与pyBox2D一起使用,但您可以轻松地将其转换为C++)

您需要具有某些属性的 Spring 对象。您的 Spring 对象需要知道它们的初始长度,刚度,body1,body2,连接坐标(b1x,b1y,b2x,b2y(在局部坐标中))

在您的情况下,您需要检查length

            body1 = spr.box2DBody1
            body2 = spr.box2DBody2

            pA = body1.GetWorldPoint(b2Vec2(spr.box2Db1x, spr.box2Db1y))
            pB = body2.GetWorldPoint(b2Vec2(spr.box2Db2x, spr.box2Db2y))
            lenVector = pB - pA
            length = lenVector.Length()
            deltaL = length - spr.initialLength
            force = spr.K * deltaL
            #normalize the lenVector
            if length == 0:
                lenVector = b2Vec2(0.70710678118654757, 0.70710678118654757)
            else:
                lenVector = b2Vec2(lenVector.x / length, lenVector.y / length)
            sprForce = b2Vec2(lenVector.x * force, lenVector.y * force)
            body1.ApplyForce(sprForce, pA)
            body2.ApplyForce(-sprForce, pB)

10-06 10:37
查看更多