使用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)