-1

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.

House
  • 73,224
  • 17
  • 184
  • 273
Dusty
  • 167
  • 2
  • 2
  • 10
  • @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. – House 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) – House 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
  • Probably because you're not detecting when you're done. You should add code that detects when the entity is "close enough". If it's at the point or within some small distance to it, just stop there. – House May 17 '13 at 17:59
  • Thanks. can't believe I missed that. Sorry for being so slow at this today. – Dusty May 17 '13 at 18:05
  • Wait, why was the original question edited to remove the code completely? This seems like bad practice as no one can now learn from the original question. I didn't think this was a terrible question, just a simple mistake combined with some misapplication of physics calculations. – Ian T. Small May 17 '13 at 21:36

2 Answers2

4

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.

Ian T. Small
  • 726
  • 5
  • 5
1

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.

House
  • 73,224
  • 17
  • 184
  • 273