4
\$\begingroup\$

I am writing a script in unity that applies a force to the object to advance it a set distance in an environment without friction or drag, producing a cosine force curve.

However, as the target approaches the destination, the force to apply is less than the value specified by the curve as the time unit is too large and will cause the object to reverse direction.

To resolve this, I estimate what the speed will be after applying this frames force and, if that reverses the direction, we take a proportion of the force.

It is working well around 4 times out of 5, but every so often it will not detect the reverse in direction and will apply the force for an extra frame or 2, causing the object to back up.

Closer investigation revealed that basically the problem stems from my estimate being significantly (some times up to 0.05) different from the velocity the next frame. I compute it as follows:

Vector3 currentVelocity = ship.rigidbody.velocity;
Vector3 direction = ship.transform.right;

// this is the value I use for the "actual" speed
float velocityAlongDir = Vector3.Dot(currentVelocity, direction); 

// this is my estimate
float estimatedVelocity = velocityAlongDir + (applyingForce * lDeltaTime);

Where the applyingForce is applied thus:

ship.rigidbody.AddForce((applyingForce * ship.rigidbody.mass) * transform.right);

Some sample data:

Predicted velocity: 0.3048308
Actual velocity: 0.2880591
Predicted velocity: 0.2068605
Actual velocity: 0.1900333
Predicted velocity: 0.09798826
Actual velocity: 0.1900333
Predicted velocity: 0.1082982
Actual velocity: -0.007007703

As you can see by the last entry, the predicted value doesn't change sing, but the real value does. Trying to work around this using does it go below a small value get different problems where the current velocity is too small etc.

Any idea why my calculation for next frame velocity seems so wrong and is there anything I can do about it?

Update

As pointed out in the comments, I needed to apply the force in the FixedUpdate and calculate my next frames velocity using Time.fixedDeltaTime. However, the following can happen, presumably in adverse frame conditions:

Predicted Velocity: 15.67547
Actual Velocity: 15.67547
Predicted Velocity: 17.54726
Actual Velocity: 15.67547 // note the same as the previous update, there has been no physics step!
Predicted Velocity: 17.51759 // estimate is subtly different, because my own timer has advanced

I fixed this by using fixedTime as opposed to fixedDeltaTime. However, then when I do a double update I am wrong for that frame, its like the physics step is trying to make up for the lost time:

// all going well...
Predicted Velocity: 52.25977
Actual Velocity: 52.25977
Predicted Velocity: 52.40138

// the estimate is wrong, we are moving at the same speed => no physics update
Actual Velocity: 52.25977
// we predict the same velocity for next frame
Predicted Velocity: 52.40138
// but we are wrong, like it is trying to catch up for lost time
Actual Velocity: 52.543

// then after that point we are precisely right
Predicted Velocity: 52.66479
Actual Velocity: 52.66479

This wouldn't be an issue except in the edge case where we do this double step precisely at the point we need to detect when the speed will change and apply the ratio. Since the physics step seems to play catch up, I miss the fact we changed speed.

\$\endgroup\$
  • 5
    \$\begingroup\$ It seems that you are computing physics in the update method, whereas physics ought to be computed in the fixedUpdate method. \$\endgroup\$ – Appleshell Dec 18 '13 at 3:30
  • \$\begingroup\$ @AdamS That was it, thanks. If you post an answer I'll accept. One thing worth noting in it: it was not sufficient to move the AddForce call in to the FixedUpdate but was sufficient to make the estimated velocity calculation depend on Time.fixedDeltaTime. In fact, leaving the calculation in the Update made the "estimate" accurate to all the decimal places printed (whereas in Fixed, only the first 3 matched) and stops the ship dead, rather than moving at a small velocity. \$\endgroup\$ – T. Kiley Dec 18 '13 at 10:11
  • \$\begingroup\$ @AdamS I have just discovered a new issue (see update) any insight would be greatly appreciated :) \$\endgroup\$ – T. Kiley Dec 19 '13 at 10:13
  • \$\begingroup\$ Have you moved all relevant code to FixedUpdate(), it sounds like some is still running in Update(). \$\endgroup\$ – Kelly Thomas Dec 19 '13 at 22:45
2
\$\begingroup\$

I resolve this (and a related question I asked on SO) as follows.

The first issue, as AdamS pointed out was that I was applying the force in the Update not the FixedUpdate. This resolved the large discrepancies originally posted.

The second issue, where it wouldn't do an FixedUpdate came from the fact that I was still advancing the time as if it had done a fixed update each update, so I used fixedTime so I could tell if there had been an update.

The last case (in this question) came from the fact the forces were accumulating so when there had been 2 updates between fixed updates, it was applying double the force.

This caused its own issues as, because the forces were only being applied per fixed update, low frame rate would cause the ship to not go fast enough (see SO question).

\$\endgroup\$

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.