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.

This question already has an answer here:

I'm trying to make a simple object move to a desired location using its velocity. But I'm having trouble with it over shooting its target.

I have to use velocity, I can't simply lerp the position, although something like lerping is the effect I'm looking for.

share|improve this question
    
@Byte56 That's not quite what I'm looking for. Something i forgot to mention is I can't have a constant Deceleration distance or speed as there is no max velocity. –  Dusty May 17 '13 at 17:22
    
The "deceleration" distance can be calculated based off the current speed. Just calculate the distance it would take to stop using your maximum acceleration given the current velocity. –  Byte56 May 17 '13 at 17:25
    
float decelDist = distanceTo / Velocity.magnitude; ? –  Dusty May 17 '13 at 17:31
    
You need to account for the maximum acceleration: So it's more like distanceToComeToStop = (speed*speed)/(2*maxAccel) –  Byte56 May 17 '13 at 17:36
    
I'm still messing something up, it slows until the point and then speeds up again in the opposite direction and repeats –  Dusty May 17 '13 at 17:57
show 3 more comments

marked as duplicate by Byte56, msell, Anko, Josh Petrie, bummzack May 21 '13 at 9:37

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

2 Answers

up vote 3 down vote accepted

There are two problems. One, you are setting the velocity directly yet applying it as a force by taking into account the ridged body mass. Two, your "slowing down" is exactly the same as you are speeding up, you are not inverting the speed adjustment.

Though I am unsure why (if the object has a ridged body) you are performing this by hand instead of with physics forces, may I suggest:

You effectively need to answer two questions at any given time, with one more optional questions.

  1. How far will it take me to stop?
  2. How far is my target?
  3. Optional: How much more distance can I accelerate until I would be unable to decelerate in time.

To stop we'd the time for our velocity to decelerate to zero:

  • Let v be the current velocity and v' the velocity in time t. 0=(v - v') or v' = v
  • Then letting a be acceleration a*t = v or t = v/a

We then need the distance this takes us:

  • First calculate the average velocity A A= (v+v')/2 or A= v/2
  • Then the stopping distance d is a matter of applying time to the average velocity d = tA or d = tv/2 or d = (v/a)v/2

The code is as follows

protected virtual void Movement(){
    targetDistance= Vector3.Distance(transform.position, wantedPos);
    stoppingDistance = GetCurrentStoppingDistance(Velocity.magnitude, acceleration);
    public Vector3 engineVelocity = transform.forward * acceleration; //assume we are accelerating forward at first
    if(targetDistance<= stoppingDistance ){
        engineVelocity = -1 * engineVelocity; //decelerate instead;
    }
    else if(targetDistance<= (stoppingDistance * 1.05) ){
        engineVelocity = Vector3.zero; //stop accelerating  5% of the distance before we need to start slowing to avoid over shoots between frames
    }
    /*
     * set the velocity as a velocity (no mass adjustment needed, this isn't a force being applied. 
     * Note we SHOULD be using the ridged body ApplyForce and supply it with a VelocityChange force 
     * type instead) 
     */
    Velocity += engineVelocity; 
}

private float GetCurrentStoppingDistance(float velocity, float accelerationPossible){
    return (velocity/acceleration) * velocity * 0.5f;
}

Remember: Velocity changes do not take mass into consideration, only application of a force or an impulse would require that.

share|improve this answer
add comment

To sum up the comments:

Use the following strategy for the arrival behavior. This paper has more information.

target_offset = target - position
distance = length (target_offset)
ramped_speed = max_speed * (distance / slowing_distance)
clipped_speed = minimum (ramped_speed, max_speed)
desired_velocity = (clipped_speed / distance) * target_offset
steering = desired_velocity - velocity

You can calculate the slowing_distance dynamically using the current speed of your entity and it's maximum acceleration with the following equation:

distanceToComeToStop = (speed*speed)/(2*maxAccel)

Finally, you need to remember to stop once you get there! Pick a small distance that makes the entity "close enough". If your entity is within this distance and moving slow enough to stop using the maximum acceleration, set your entity speed to 0 and stop checking if it's close enough.

share|improve this answer
add comment

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