3
\$\begingroup\$

Given a body with an orientation angle and a point of interest or targetAngle, is there an elegant solution for keeping the body oriented towards the point of interest by applying torque or impulses?

I have a naive solution working below, but the effect is pretty 'wobbly', it'll overshoot each time, slowly getting closer to the target angle - an undesirable effect in my case. I'd like to find a solution that is more intelligent - one that can accelerate to near the target angle then decelerate and stop right at the target angle (or within a small range).

If it helps, I'm using box2d and the body is a rectangle.

def gameloop(dt):
    targetAngle = get_target_angle()
    bodyAngle = get_body_angle()
    deltaAngle = targetAngle - bodyAngle
    if deltaAngle > PI:
        deltaAngle = targetAngle - (bodyAngle + 2.0 * PI)
    if deltaAngle < -PI:
        deltaAngle = targetAngle - (bodyAngle - 2.0 * PI)
    # multiply by 2, for stronger reaction
    deltaAngle = deltaAngle * 2.0;
    body.apply_torque(deltaAngle);

One other thing, when body has no linear velocity, the above solution works ok. But when the body has some linear velocity, the solution above causes really wonky movement. Not sure why, but would appreciate any hints as to why that might be.

\$\endgroup\$
2
\$\begingroup\$

From what I've understood from your post, this is essentially an Arrive behaviour. Arrival is a fairly simple behaviour to implement, and you don't have to use angles to get an angle back either.

Vector toTargetVector = targetPosition - bodyPosition;
double distanceToTarget = toTargetVector.Length();

// It's very simple to get the angle from here, just use atan2 (or the equivalent function in whatever language you're using)
float angleToTarget = atan2( toTargetVector.y, toTargetVector.x );

if( distanceToTarget > 0.0 )
{
    double rateOfDeceleration = 0.2;    // This can be tweaked to whatever value you like
    double speed = distanceToTarget / rateOfDeceleration;

    Vector desiredVelocity = ( toTargetVector * speed ) / distanceToTarget;

    return ( desiredVelocity - body.velocity );
}

This behaviour (among the rest of them) is very clearly detailed in Mat Buckland's book "Programming Game AI by Example".

If you want a very, very simple behaviour just to get your target angle correct then use Seek.

Vector toTargetVector = targetPosition - bodyPosition;

double distanceToTarget = toTargetVector.Length();

float angleToTarget = atan2( toTargetVector.y, toTargetVector.x );

And that's basically it, you can then do all your physics stuff after this basic vector stuff.

Hope that helps.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the book reference. I'll check that out. I guess I am trying to do a Seek behavior, but I was trying to avoid setting velocity, position and rotation explicitly because it could interfere with the box2d simulation. Instead I was trying to maneuver the body by applying impulses, torque and/or force (proving to be difficult for me). Also, I'm trying to align the body's orientation with its velocity. \$\endgroup\$ – azymm Dec 31 '10 at 3:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.