# How do I make a moving object stop smoothly at the end of a path?

There are a dozen ways I could word this question, but to keep my thoughts in line, I'm phrasing it in line with my problem at hand.

So I'm creating a floating platform that I would like to be able to simply travel from one designated point to another, and then return back to the first, and just pass between the two in a straight line. However, just to make it a little more interesting, I want to add a few rules to the platform.

1. I'm coding it to travel multiples of whole tile values of world data. So if the platform is not stationary, then it will travel at least one whole tile width or tile height.
2. Within one tile length, I would like it to accelerate from a stop to a given max speed.
3. Upon reaching one tile length's distance, I would like it to slow to a stop at given tile coordinate and then repeat the process in reverse.

The first two parts aren't too difficult, essentially I'm having trouble with the third part. I would like the platform to stop exactly at a tile coordinate, but being as I'm working with acceleration, it would seem easy to simply begin applying acceleration in the opposite direction to a value storing the platform's current speed once it reaches one tile's length of distance (assuming that the tile is traveling more than one tile-length, but to keep things simple, let's just assume it is)- but then the question is what would the correct value be for acceleration to increment from to produce this effect? How would I find that value?

• I don't have time for a full answer at the moment, but take a look at this: red3d.com/cwr/steer/gdc99, specifically the "Arrival" section. Mimic that behavior to slow to a stop and reverse it to speed up from a stop.
– House
Oct 2, 2012 at 0:47
• Bookmarked. That is a wealth of valuable information you have just enlightened me to, Sir. Oct 2, 2012 at 1:00
• This "desired_velocity = (clipped_speed / distance) * target_offset" sort of makes sense, but not exactly. Once I find desired_velocity, to I subtract it from the object's current speed? Oct 2, 2012 at 1:59
• I use it to update the acceleration value: acceleration = desired_velocity - currentVelocity Then apply that acceleration as you normally would. I'll create an answer in a bit further showing what I do.
– House
Oct 2, 2012 at 2:11

Using these steering behaviors as a guide. Looking at the arrive behavior:

Arrival behavior is identical to seek while the character is far from its target. But instead of moving through the target at full speed, this behavior causes the character to slow down as it approaches the target, eventually slowing to a stop coincident with the target.

We can create an "arrive at" function like something similar to this:

arriveAtPoint(Vector2f position, Vector2f target) {
float slowing_distance = 1;
Vector2f target_offset = target - position;
float distance = target_offset.length();
float ramped_speed = currentVelocity * (distance / slowing_distance);
float clipped_speed = Math.min(ramped_speed, currentVelocity);
targetLinearVelocity = target_offset.scale(clipped_speed / distance);
acceleration = targetLinearVelocity -linearVelocity;
}


This will update the acceleration we need to use to apply to the object in motion.

• And just for clarification, linearVelocity would be the velocity at which our object would have been currently traveling after the prior update? Oct 2, 2012 at 3:48
• Your phrasing is pretty strange. But, linearVelocity == currentVelocity.
– House
Oct 2, 2012 at 3:53
• I disagree with this approach on the basis that it is over-complicated. It's possible to do this with a simple tween using equations of motion (the SUVAT formulas). A little algebra and you can calculate the inputs required to hit a desired target precisely. Oct 2, 2012 at 7:03
• It would be helpful if you could elaborate that with an answer? Oct 2, 2012 at 19:05
• @AndrewRussell I'd like to see that answer too.
– House
Oct 2, 2012 at 20:26

It seems that you want a effect just like the smoothstep:

If you have leftmost point, the rightmost point the platform should achieve, and the time it should use to go make a full sequence, something like this may be ok:

foreach frame:

float smoothstep(float t, int level = 1)
{
float ret = t;
for(int i = 0; i < level; ++i)
{
ret = pow(ret, 2) * (3 - 2 * ret);
}
return ret;
}

currentTime += deltaTime;
if(currentTime > fullTime) currentTime -= fullTime;
float halfTime = fullTime / 2.0;
float t = abs(currentTime - halfTime) / halfTime;
t = smoothstep(t, 1);
platformPosition = rightPoint * t + leftPoint * (1 - t);


if you're using a physics engine, you can make it with impulses, shouldn't be that hard to translate. If you want a even smoother process, you can increase the smoothstep level.

You can use XnaTweener that provides easing functions that interpolate values from one point to another in a easy way...

Here is a reply with some code based in the Xna Tweener project and a video showing how it performs...

https://gamedev.stackexchange.com/a/26872/8390

[EDIT]

You should have a sequence of keys that defines the platform movement, like this:

public class MovementKey
{
public float Time = 0;
public float Duration;
public Vector2 Traslation;            // Traslation is relative to previous key
public TweeningFunction Function;

internal float GetRatio( float Elapsed )
{
// Always return a value in [0..1] range
//    0 .. Start position relative to accumulated traslations of previous keys
//    1 .. Target relative position reached.. then should go to next key if avalaible
return Function( Elapsed, 0, 1, Duration );
}
}


And then you can handle the movement this way:

public class Movement {

List<MovementKey> Keys;

public void Update( float Seconds)
{

float ratio;
if (Playing) Elapsed += Seconds;

while ( index!= Keys.Count - 1 && Elapsed > Keys[iKey + 1].Time )
{
Traslation += Keys[iKey].Traslation;  // Relative
index++;
}

if ( index == Keys.Count - 1 && Elapsed > Keys[iKey].Time + Keys[iKey].Duration )
{
ratio = 1;
if ( DoLoop )
{
Elapsed -= (Keys[index].Time + Keys[iKey].Duration);
Index = 0;
Traslation = Vector2.zero;
}
}
else {
ratio = Keys[index].GetRatio( Elapsed - Keys[index].Time );
}

Position = DefaultPosition + Traslation + ratio * Keys[index].Traslation;
}


"DefaultPosition" is the start position, "Traslation" accumulates movement of several keys, and each key traslation is relative to the previous key, so when you multiply it by a ratio factor [0..1] it returns the interpolated relative traslation walked to reach that key from the previous key...

Here you have another video that shows a platform movement defined as described here...