Как создать резиновую нить в Box2D? - PullRequest
2 голосов
/ 08 февраля 2012

Используя Box2d, как создать резиновую нить (резинку / упругую веревку), как Парашютный ниндзя (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
}

Я использую расстояние и веревочные соединения, задаю разные значения параметров noiseingRatio и частоты Гц, но эффект далек от того, чтобы служить примером (моя нить долго приходила в исходное состояние, и не такая упругая.).

Ответы [ 3 ]

3 голосов
/ 10 февраля 2012

Вы можете моделировать пружины, применяя силы.На каждом временном шаге обновляйте силы на соединенных телах (будьте телами, если необходимо, тоже).Если одно из тел является землей (или статическим телом), вам не нужно прилагать к земле какую-либо силу, а только динамическое тело.

Обычная пружина будет прикладывать как силы натяжения, так и силы сжатия (тягаи толкать) в зависимости от прогиба.В вашем случае у вас есть банджи, поэтому не будет силы сжатия, только натяжение (тянуть).

Это формула, которая вам нужна:

F = K * x

Где F - сила, K - жесткость пружины (сила / прогиб), а x - прогиб.Прогиб рассчитывается как разница между начальной длиной и текущей длиной (расстоянием между точками соединения).Знак F определяет, тянет ли он или толкает.Как только вы вычислите F, вам нужно применить его вдоль линии, соединяющей две точки пружинного соединения.Для достижения баланса сил вам необходимо применить эту силу в противоположных направлениях (одно из тел становится положительным, а другое - отрицательной).Это потому, что сэр Ньютон так говорит.

Вот пример (работает с pyBox2D, но вы можете легко преобразовать это в C ++)

Вам нужны объекты Spring с некоторыми свойствами.Ваши пружинные объекты должны знать их начальную длину, жесткость, body1, body2, координаты соединения (b1x, b1y, b2x, b2y (в локальных координатах))

В вашем случае вам нужно проверить, если длина

            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 голос
/ 08 февраля 2012

Я очень сомневаюсь, что они используют какие-либо соединения там.Вероятно, они просто берут расстояние между текущей позицией парня-ниндзя и серединой двух постов, чтобы вычислить направление и начальный импульс ... и просто рисуют две линии между постами и парнем-ниндзя.

0 голосов
/ 08 февраля 2012

Лучшая физическая реализация, добавленная в игры, которые я видел, была сделана парнем с дипломом инженера. Он использовал вычисления, которые вы сделали бы в физике / технике, переведенной на C ++. Все от простой гравитации, отдачи, тяги до скоростей вращения, вызванных случайными взрывами. Вся математика была разделена на модуль, отличный от анимации.

Я бы предложил поискать формулы для свойств резинок, а также учесть, что у вас есть три ситуации для эластичной ленты: 1) Формируется сила, чтобы растянуть его 2) Форма теперь определяется упругими свойствами ленты 3) Форма больше не касается полосы, и лента свободно колеблется под действием собственного веса и инерции

Чем ближе вы будете использовать истинные физические расчеты, тем реалистичнее они будут выглядеть. Я уверен, что вы можете обмануть это, чтобы облегчить себе, но люди по своей природе хороши, видя ложь.

...