-1
\$\begingroup\$

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.

\$\endgroup\$
8
  • \$\begingroup\$ @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. \$\endgroup\$
    – Dusty
    May 17, 2013 at 17:22
  • \$\begingroup\$ 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. \$\endgroup\$
    – House
    May 17, 2013 at 17:25
  • \$\begingroup\$ float decelDist = distanceTo / Velocity.magnitude; ? \$\endgroup\$
    – Dusty
    May 17, 2013 at 17:31
  • \$\begingroup\$ You need to account for the maximum acceleration: So it's more like distanceToComeToStop = (speed*speed)/(2*maxAccel) \$\endgroup\$
    – House
    May 17, 2013 at 17:36
  • \$\begingroup\$ I'm still messing something up, it slows until the point and then speeds up again in the opposite direction and repeats \$\endgroup\$
    – Dusty
    May 17, 2013 at 17:57

2 Answers 2

4
\$\begingroup\$

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.

\$\endgroup\$
1
\$\begingroup\$

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.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged .