Reputation: 23
I'm trying to create an autonomous agent with arriving behaviour based on Reynolds classic Boids paper and more specifically Dan Shiffman's implementation on natureofcode.com. Both of these approaches are easy to understand (and work) but they both assume a fixed nominal update step rather than querying the elapsed time since the last frame update and applying this time delta during the Euler integration step. Ie they suggest simply:
//pseudocode
acceleration.add(force);
velocity.add(acceleration);
location.add(velocity);
however if I want to include a time delta then various physics papers suggest I should rewrite this as:
//pseudocode
delta = timeElpasedSinceLastFrameUpdate();
acceleration.add(force);
deltaAcceleration = acceleration.mult(delta);
velocity.add(deltaAcceleration );
deltaVelocity = velocity.mult(delta);
location.add(deltaVelocity);
This also works until I try to implement the steering behaviours and specifically the arriving behaviour. For reference to the methodology see example 6.2 in the link here:
Nature of Code Steering Behaviours
The problematic step (in pseudocode) is steeringForce = desired - velocity;
Without a time delta applied the contribution of '- velocity' to the steering force correctly counteracts the currently held velocity vector and brings the object to a decelerating stop at the arrival destination.
With a time delta applied however the steeringForce is effectively moderated by the fractional time delta when I multiply acceleration by delta and hence doesn't apply sufficient deceleration to the accumulated velocity to bring the object to a halt in time and I get oscillating behaviour.
I can 'fix' this by not multiplying accumulated forces (i.e. acceleration) by time delta but this doesn't seem correct.
So, my question:
How should a steeringForce for arrival behaviour be generated to account for variable delta time?
Any help gratefully appreciated!
Upvotes: 2
Views: 485
Reputation: 3473
EDIT: I missed the main part of your question. There are many ways to get the result you want, but they do so by different means. The easiest I can come up with is probably to skip the steeringForce
for now all together and instead just modify the velocity.
We want a vector such that
desired_velocity = velocity + correction
This is the same as you wrote previously (but for 'steeringForce'):
correction = desired_velocity - velocity
By doing velocity + correction
you will immediately get to the desired velocity, which is usually not what you want as it leads to a very jerky motion. Instead, you could clamp the correction to some value which would lead to a smoother motion:
len = length(correction)
corr_length = len > max_correction ? max_correction : len
correction = correction/len*corr_length
And now you can do
velocity += correction
This should lead to a somewhat dynamic motion, without oscillation.
Explicit time step integration (e.g. an forward Euler in your case) is usually written as
new_acceleration = old_acceleration + (delta_t/mass)*force
^^ note
And similarly,
new_velocity = old_velocity + delta_t*acceleration
new_position = old_position + delta_t*velocity
So to answer your question, you need to multiply by the time step before accumulating:
acceleration.add(force.mult(delta_t/mass));
velocity.add(acceleration.mult(delta_t));
location.add(velocity.mult(delta_t));
Upvotes: 1