Сделать вихрь в Box2D - PullRequest
       16

Сделать вихрь в Box2D

2 голосов
/ 19 декабря 2011

Я пытаюсь создать спиральный вихрь в Box2D на C ++ / Objective C, применяя силы.Я хотел бы осознать, что это вихрь, который отталкивает тела от точки или притягивает их.Думаю, мне придется применить более одной силы.

Моя точка входа в эту проблему:

Я думаю, что мне нужно применить 3 силы: - Импульс, чтобы привлечь или оттолкнуть тело от центра.- Импульс заставить его двигаться по спирали, но ... как?- Крутящий момент, чтобы вращать само тело, если импульс не делает это для меня.

Ответы [ 2 ]

3 голосов
/ 22 декабря 2011

Однажды я сделал вращающуюся платформу, создав круговой датчик, который применил тангенциальное изменение скорости к телу, заданному круговым векторным полем. Круговое векторное поле, которое я использовал, было таким:

V = (y, -x)

Визуальное представление этого векторного поля можно найти здесь: http://kasadkad.files.wordpress.com/2009/09/derham1.png?w=450&h=427

Y и X - это относительное положение тела к центру датчика, поэтому вы можете сделать что-то вроде этого:

Vector getTangentVector(Vector relativePosition, bool invert)
{
    Vector vec;
    if(invert) //if it's cw or ccw
    {
        vec.setY(relativePosition.x());
        vec.setX(-relativePosition.y());
    }
    else
    {
        vec.setY(-relativePosition.x());
        vec.setX(relativePosition.y());
    }
    return vec;
}

Затем на методе обновления моей программы я делаю что-то вроде этого:

for (b2ContactEdge* ce = platformBody->GetContactList(); ce; ce = ce->next)
{

    b2Contact* c = ce->contact;

    if(c->IsTouching())
    {
        const b2Body* bodyA = c->GetFixtureA()->GetBody();
        const b2Body* bodyB = c->GetFixtureB()->GetBody();

        const b2Body* targetBody = (bodyA == platformBody)?bodyB:bodyA;

        Vector speed = getTangentImpulse(
                          getRelativePosition(platformBody, targetBody),
                          true);


        speed *= CONSTANT; // CONSTANT = 1.8, 
                           // this is to account for the targetBody attrition, 
                           // so it doesn't slip on the platform

        Vector currentSpeed;
        currentSpeed.setX(targetBody->GetLinearVelocity().x);
        currentSpeed.setY(targetBody->GetLinearVelocity().y);



        Vector diff = speed - currentSpeed;
        diff *= 0.01; //should depend on time, but this worked nicely. It makes the
                      //body change its linear velocity to be the same as "speed" at a 
                      //0.01 change rate.

        currentSpeed += diff;
        targetBody->SetLinearVelocity(
                               b2Vec2(currentSpeed.x(), 
                               currentSpeed.y()));

    }

}

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

Тем не менее, это произвело эффект, который мне был нужен, поэтому я надеюсь, что это сработает для вас. Для вихря, я думаю, вам просто нужно соединить сустав, например, мышиный, прикрепить к центру и захватить тело. Если вы используете только сустав, вам будет трудно сделать его достаточно сильным, чтобы захватить тело, но достаточно слабым, чтобы заставить его вращаться вокруг центра. Вместе с моим кодом было бы легче достичь этого, просто поиграв с константами.

Надеюсь, это поможет.

edit: Я только что вспомнил, что с помощью кода платформы вы также гарантируете направление вращения, что невозможно только при соединении.

0 голосов
/ 05 января 2014

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

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

Я называю "myBodyA" телом, которое является центром вихря.

Из Руководства Box2d:

b2DistanceJointDef jointDef;
jointDef.Initialize(myBodyA, myBodyB, worldAnchorOnBodyA, worldAnchorOnBodyB); jointDef.collideConnected = true;
world->CreateJoint(&jointDef);

Вам придется приложить некоторую силу к своему телу (давайтескажем, это был myBodyB), чтобы заставить его двигаться в правильном направлении, чтобы он вращался вокруг myBodyA.Это потребует математики.

То, что вы хотите сделать, это вычислить вектор, который указывает перпендикулярно вектору, указывающему от myBodyB к myBodyA.Вы можете сделать это, найдя вектор из myBodyB в myBodyA, нормализовав его, взяв его перекос (поворот на PI / 2), а затем используя его как направление силы.Что-то вроде:

// Calculate Tangent Vector
b2Vec2 radius = myBodyB.GetPosition()-myBodyA.GetPosition();
b2Vec2 tangent = radius.Skew();
tangent.Normalize();

// Apply some force along tangent
myBodyB.ApplyForceToCenter(body->GetMass()*acceleration*vTangent);

Если вы прочитаете это правильно, вы увидите F = m * a * tangentVector;то есть вы прикладываете силу в направлении касательной.Я считаю, что он будет вращаться по часовой стрелке (если я правильно сделал математику).В любом случае, отрицательная сила будет перемещать его в противоположном направлении.

Чтобы остановить вращение тела, вы можете использовать SetLinearDamping (dampingValue) для него.Поэтому, пока вы применяете силу, она будет продолжать вращаться.Если вы прекратите применять силу, она должна аккуратно остановиться.Вы можете контролировать скорость увеличения / уменьшения с помощью значения ускорения и параметров noiseingValue.

Если вы действительно хотите хороший контроль над скоростью, я думаю, вы можете сделать это, чтобы ограничить скорость:

b2Vec2 linVel = myBodyB.GetLinearVelocity();
linVel.Normalize();
linVel *= maxSpeed;
myBodyB.SetLinearVelocity(linVel);

Было ли это полезно?

...