问题
i have a question about moving a Box2D body to a specific position without using this for example.
body->SetTransform(targetVector,body->GetAngle())
I have some code which works for applyForce (here):
const float destinationControl = 0.3f;
b2Vec2 missilePosition = _physicalBody->GetPosition();
b2Vec2 diff = targetPosition - missilePosition;
float dist = diff.Length();
if (dist > 0)
{
// compute the aiming direction
b2Vec2 direction = b2Vec2(diff.x / dist, diff.y / dist);
// get the current missile velocity because we will apply a force to compensate this.
b2Vec2 currentVelocity = _physicalBody->GetLinearVelocity();
// the missile ideal velocity is the direction to the target multiplied by the max speed
b2Vec2 desireVelocity = b2Vec2(direction.x * maxSpeed, direction.y * maxSpeed);
// compensate the current missile velocity by the desired velocity, based on the control factor
b2Vec2 finalVelocity = control * (desireVelocity - currentVelocity);
// transform our velocity into an impulse (get rid of the time and mass factor)
float temp = (_physicalBody->GetMass() / normalDelta);
b2Vec2 finalForce = b2Vec2(finalVelocity.x * temp, finalVelocity.y * temp);
_physicalBody->ApplyForce(finalForce, _physicalBody->GetWorldCenter());
}
But the when the maxSpeed
is to high the body move over the point to fast.
So does anyone know how to calculate a force (ApplyForce
) or an impluse (ApplyLinearImpulse
) to move the body to a target position (very exactly) in a specific time.
Or a solution with the code above. I mean calculate the maxSpeed
to move the body in a specific time to the target position.
In my google search i found the interesting article from iforce about projected trajectory (here). Maybe this could be help too?
Thank you in advance
回答1:
I think you have it mostly correct, but you are not checking to see if the body will overshoot the target in the next time step. Here is what works for me:
b2Vec2 targetPosition = ...;
float targetSpeed = ...;
b2Vec2 direction = targetPosition - body->GetPosition();
float distanceToTravel = direction.Normalize();
// For most of the movement, the target speed is ok
float speedToUse = targetSpeed;
// Check if this speed will cause overshoot in the next time step.
// If so, we need to scale the speed down to just enough to reach
// the target point. (Assuming here a step length based on 60 fps)
float distancePerTimestep = speedToUse / 60.0f;
if ( distancePerTimestep > distanceToTravel )
speedToUse *= ( distanceToTravel / distancePerTimestep );
// The rest is pretty much what you had already:
b2Vec2 desiredVelocity = speedToUse * direction;
b2Vec2 changeInVelocity = desiredVelocity - body->GetLinearVelocity();
b2Vec2 force = body->GetMass() * 60.0f * changeInVelocity;
body->ApplyForce( force, body->GetWorldCenter(), true );
回答2:
There is a way for single-time applied force to move by given distance (previous answer suggests that you can correct error in calculation by additional force in future frames):
public static void applyForceToMoveBy(float byX, float byY, Body body) {
force.set(byX, byY);
force.sub(body.getLinearVelocity());
float mass = body.getMass();
force.scl(mass * 30.45f);
body.applyForceToCenter(force, true);
}
Known limitations:
1) LinearVelocity effect was not tested;
2) calculation was tested with body linear damping = 0.5f. Appreciate, if somebody know how to add it into formula;
3) magic number 30.45f - maybe this could be fixed by point 2 or by world frame delta.
来源:https://stackoverflow.com/questions/24516945/calculate-correct-impluse-or-force-to-move-a-box2d-body-to-a-specific-position