如何在Box2D中创建橡胶线?

时间:2012-02-08 11:46:18

标签: c++ objective-c box2d game-physics

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

enter image description here

-(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
}

我使用距离和绳索关节,设置不同的参数dampRatio和frequencyHz,但效果远非一个例子(我的线程很长一段时间来到原始状态,而不是那么有弹性。)。< / p>

3 个答案:

答案 0 :(得分:3)

您可以通过施加力来模拟弹簧。在每个时间步骤更新连接体上的力(如果需要也唤醒身体)。如果其中一个物体是地面(或静止的物体),那么你就不需要对动力体施加任何力。

常规弹簧将根据偏转施加拉力和拉力(拉力和推力)。在你的情况下,你有一个蹦极,所以没有压缩力只是张力(拉)。

这是您需要的公式:

F = K * x

其中F是力,K是弹簧刚度(力/偏转),x是偏转。偏差被计算为初始长度和当前长度(连接点之间的距离)之间的差。 F的符号决定它是拉还是推。计算F后,您需要沿连接两个弹簧连接点的线应用它。为了满足力平衡,你需要在相反的方向上施加这个力(其中一个物体变为正,另一个物体获得负力)。这是因为牛顿爵士这么说。

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

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

在您的情况下,您需要检查长度&lt; spr.initialLength,如果这是True,则不施加任何力。

            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)

答案 1 :(得分:1)

我非常怀疑他们在那里使用任何关节。他们可能只是把忍者家伙的当前位置和两个帖子的中间之间的距离来计算方向并开始冲动......并且只是在帖子和忍者之间画两条线。

答案 2 :(得分:-4)

我见过的最好的物理实现是由一个拥有工程学位的人完成的。他将您在物理/工程中所做的计算翻译成C ++。从简单的重力,反冲,推力到偶然爆炸引起的旋转速度的一切。所有数学都被分成了一个与动画不同的模块。

我建议查找弹性材料属性的公式,并考虑弹性带有三种情况:  1)正在施加成形力以将其拉回  2)现在形状由带的弹性特性驱动  3)形状不再接触带子,带子因自身重量和惯性而剧烈摆动

越接近使用真实的物理计算,它就越真实。我相信你可以捏造它以使自己更容易,但人类天生就善于看到假货。