Search code examples
box2dgeometry

Box2d Rotate body around point using forces or impulses


I have a body that should move around some point. If I press "right" body moves clockwise, if I press left body moves counterclockwise direction. Which force I should apply to do that?


Solution

  • I think you need to create a static body at the point you wish to rotate around and then connect your rotating body and it using a b2DisanceJoint. From the Box2d Manual:

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

    Then you will have to apply some force to your body (let's say it was myBodyB) to get it moving in the right direction so it rotates around myBodyA. This is going to require some math.

    What you want to do is calculate the vector that points perpendicular to the vector pointing from myBodyB to myBodyA. You can do this by finding the vector from myBodyB to myBodyA, normalizing it, taking the skew of it (rotate by PI/2), and then using it as a force direction. Something like:

    // 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);
    

    If you read this correctly, you can see F = m * a * tangentVector; that is to say, you are applying force in the direction of the tangent. I believe it will rotate it clockwise (if I did the math right). Regardless, a negative on the force will move it in the opposite direction.

    To stop the body rotating, you can use the SetLinearDamping(dampingValue) on it. So as long as you apply force, it will continue to rotate. If you stop applying force, it should gently stop. You can control the speed up/slow down by the acceleration value and the dampingValue parameters.

    If you really want good control over the speed, I believe you can do this to clamp the speed:

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

    Was this helpful?