Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

The function below works fine, when the timesteps of the physicsengine are short enough for the function to update often. It determinates when the ship(the object) needs to start decelerating to reach 0 angular velocity by the time it reaches the target rotation. (Always using maximum torque of the ship to turn)

However, I want to simulate this in a scenario with longer timesteps. Since my function checks for when to start decelerating each update, it will miss this moment when the timesteps are longer and move past the target rotation. The ship then starts swaying back and forth (obviously).

What I need is some way to determinate the torque I need to apply to the body for it to end up at that sweetspot where it needs to decelerate. That way the ship can start decelerating when the next update occurs and hopefully end up facing the target rotation with almost 0 angular velocity!

private void TurnTowardsTarget(Vector2 target, float deltaTime)
    {
        Vector2 delta = target - body.Position;
        float targetRot = (float)Math.Atan2(delta.Y, delta.X);
        float dRot = (float)Math.Atan2(Math.Sin(targetRot - body.Rotation),
            Math.Cos(targetRot - body.Rotation));
        float angularAcceleration = maxTurnForce / body.Inertia;
        float avgDecelerationVelocity = body.AngularVelocity / 2;
        float time = dRot / avgDecelerationVelocity;
        float decelerationRequired = body.AngularVelocity / time;

        //Target rotation is to the right (positive rotations are to the right)
        if (dRot > 0)
        {
            //If the ship is rotating to the right
            if (body.AngularVelocity >= 0)
            {
                //Should we start decelerating?
                if (decelerationRequired >= angularAcceleration)
                {
                    //Decelerate
                    TurnLeft();
                }
                else
                {
                    //Keep on accelerating towards the target
                    TurnRight();
                }
            }
            else
            {
                //The ship is rotating the wrong way, turn towards the target
                TurnRight();
            }
        }

        //Target rotation is to the left (negative rotations are to the left)
        if (dRot < 0)
        {
            if (body.AngularVelocity <= 0)
            {
                //Should we start decelerating?
                if (-decelerationRequired >= angularAcceleration)
                {
                    //Decelerate
                    TurnRight();
                }
                else
                {
                    //Keep on accelerating towards the target
                    TurnLeft();
                }
            }
            else
            {
                //The ship is rotating the wrong way, turn towards the target
                TurnLeft();
            }
        }
    }

I hope I made myself quite clear, all the TurnLeft() and TurnRight() do is to apply "maxTurnForce" in the corresponding direction. Please respond if you find a solution, my brain is melting (x.

/Kimmeh!

Edit:

This is how the code looks now after implementing Sam's suggestion, it slightly overshoots the target rotation though, no matter the update-rate. And jitters back and forth from the target rotation.

I've put Math.Abs() around the time-calculation, changed sign of decelerationDecelerationRequired and changed sign of angularAcceleration depending on dRot.

        Vector2 delta = turnToTarget - body.Position;
        float targetRot = (float)Math.Atan2(delta.Y, delta.X);
        float dRot = (float)Math.Atan2(Math.Sin(targetRot - body.Rotation),
            Math.Cos(targetRot - body.Rotation));
        float angularAcceleration = maxTorque * -Math.Sign(dRot) / body.Inertia;
        float avgDecelerationVelocity = body.AngularVelocity / 2;
        float time = Math.Abs(dRot / avgDecelerationVelocity);
        float decelerationRequired = -body.AngularVelocity / time;

        float torque = (decelerationRequired - angularAcceleration) * body.Inertia;
        torqueToApply = MathHelper.Clamp(torque, -maxTorque, maxTorque);

Just to clarify, I'm using Farseer physics engine, and I apply the torque of the body right before calling the step() function of farseer. The body has a slight angular damping, so it should actually rotate a bit less than expected.

I think it's because it now smoothly adjusts to the decelerationRequired. (say if the decelerationRequired == angularAcceleration, the change of torque would be 0, when it should be +-maxTorque in order to stop in time.

share|improve this question

1 Answer 1

The problem is that TurnLeft() and TurnRight() basically work as on/off switches instead of continuously. You need to simulate what happens when the force is applied only during a fraction of the timestep. I suggest adding an argument to these functions indicating the force to be used instead of maxTurnForce: at a reasonably small scale, applying half the force is equivalent to applying it for half the time.

Assuming your current computations are correct, you already know the value of that force: it is (decelerationRequired - angularAcceleration) * body.Inertia, which should be clamped between -maxTurnForce and maxTurnForce.

Another nice thing is that the sign of the force already indicates the direction. You can therefore merge TurnLeft() and TurnRight() into a single Turn(float Force) function.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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