Применение эффекта вихря / водоворота в Box2d / Cocos2d для iPhone

Я использовалНик Веллиос & apos; руководство создать радиальную гравитацию с помощью объекта Box2D. Я в курсеСделать вихрь здесь на SO, но я не мог понять, как реализовать это в моем проекте.

Я сделал вихревой объект, который представляет собой датчик Box2D circleShape, который вращается с постоянной угловой скоростью. Когда другие объекты Box2D контактируют с этим вихревым объектом, я хочу, чтобы они вращались с той же угловой скоростью, что и вихрь, постепенно приближаясь к центру вихря. В данный момент объект притягивается к центру вихря, но он направляется прямо к центру вихря, а не вращается вокруг него медленно, как я хочу. Он также будет перемещаться в направлении, противоположном вихревому, а также при вращении вихря.

Учитывая вихрь и тело box2D, как я могу настроить тело box2d, чтобы оно вращалось вместе с вихрем, когда оно «всасывается».

Я устанавливаю вращение вихря, когда создаю его так:

b2BodyDef bodyDef;
bodyDef.type = b2_dynamicBody;
bodyDef.angle = 2.0f;
bodyDef.angularVelocity = 2.0f;

Вот как я применяю радиальную гравитацию согласноНик Веллиос & apos; образец кода.

-(void)applyVortexForcesOnSprite:(CCSpriteSubclass*)sprite spriteBody:(b2Body*)spriteBody withVortex:(Vortex*)vortex VortexBody:(b2Body*)vortexBody vortexCircleShape:(b2CircleShape*)vortexCircleShape{

    //From RadialGravity.xcodeproj
    b2Body* ground = vortexBody;
    b2CircleShape* circle = vortexCircleShape;
    // Get position of our "Planet" - Nick
    b2Vec2 center = ground->GetWorldPoint(circle->m_p);
    // Get position of our current body in the iteration - Nick
    b2Vec2 position = spriteBody->GetPosition();
    // Get the distance between the two objects. - Nick
    b2Vec2 d = center - position;
    // The further away the objects are, the weaker the gravitational force is - Nick
    float force = 1 / d.LengthSquared(); // 150 can be changed to adjust the amount of force - Nick
    d.Normalize();
    b2Vec2 F = force * d;
    // Finally apply a force on the body in the direction of the "Planet" - Nick
    spriteBody->ApplyForce(F, position);
    //end radialGravity.xcodeproj


}

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

b2Vec2 vortexVelocity = vortexBody->GetLinearVelocityFromWorldPoint(spriteBody->GetPosition() );

b2Vec2 vortexVelNormal = vortexVelocity;
vortexVelNormal.Normalize();
b2Vec2 bodyVelocity = b2Dot( vortexVelNormal, spriteBody->GetLinearVelocity() ) * vortexVelNormal;

//Using a force
b2Vec2 vel = bodyVelocity;
float forceCircleX =    .6 * bodyVelocity.x;
float forceCircleY =    .6 * bodyVelocity.y;

spriteBody->ApplyForce( b2Vec2(forceCircleX,forceCircleY), spriteBody->GetWorldCenter() );

Ответы на вопрос(2)

У меня был проект, в котором астероиды вращались вокруг центральной точки (между ними что-то прыгает ... это другая точка).

  • They are connected to the "center" body via b2DistanceJoints.
  • You can control the joint length to make them slowly spiral inward (or outward). This gives you find grain control instead of balancing force control, which may be difficult.
  • You also apply tangential force to make them circle the center.
  • By applying different (or randomly changing) tangential forces, you can make the crash into each other, etc.

Я разместил более полный ответ на этот вопросВот.

Решение Вопроса

Похоже, вам просто нужно применить другую силу в соответствии с направлением вихря в текущей точке тела. Вы можете использовать b2Body :: GetLinearVelocityFromWorldPoint, чтобы найти скорость вихря в любой точке мира. Из источника Box2D:

/// Get the world linear velocity of a world point attached to this body.
/// @param a point in world coordinates.
/// @return the world velocity of a point.
b2Vec2 GetLinearVelocityFromWorldPoint(const b2Vec2& worldPoint) const;

Так что это будет:

b2Vec2 vortexVelocity = vortexBody->GetLinearVelocityFromWorldPoint( suckedInBody->GetPosition() );

Как только вы узнаете скорость, к которой вы стремитесь, вы можете рассчитать, сколько силы требуется, чтобы перейти от текущей скорости к желаемой скорости. Это может быть полезно:http://www.iforce2d.net/b2dtut/constant-speed

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

b2Vec2 vortexVelNormal = vortexVelocity;
vortexVelNormal.Normalize();
b2Vec2 bodyVelocity = b2Dot( vortexVelNormal, suckedInBody->GetLinearVelocity() ) * vortexVelNormal;

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

РЕДАКТИРОВАТЬ:

Сила, которую вы применяете, должна основываться наdifference между текущей скоростью (bodyVelocity) и желаемой скоростью (vortexVelocity), т.е. если тело уже движется вместе с вихрем, тогда вам не нужно применять какую-либо силу. Посмотрите на последний блок кода в подразделе «Использование сил». в ссылке, которую я дал выше. Последние три строки там делают в значительной степени то, что вам нужно, если вы замените 'avel; apos; и "требуемый Vel"; с размерами вашего тела Velocity и vortexVelocity векторы:

float desiredVel = vortexVelocity.Length();
float currentVel = bodyVelocity.Length();
float velChange = desiredVel - currentVel;
float force = body->GetMass() * velChange / (1/60.0); //for a 1/60 sec timestep
body->ApplyForce( b2Vec2(force,0), body->GetWorldCenter() );

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

Ваш ответ на вопрос