- Home /
Slow down in the same time over different distances
Hi,
I'm trying to slow down a object over different distances in the same time, say 3 seconds.
My slow down code is.
function lerpSpeed (speed: float, lerpSpeedTime: float)
{
incomingFlightSpeed = flightPathScript.flightSpeed;
i = 0;
while(i < 1)
{
i += Time.deltaTime/lerpSpeedTime;
i = Mathf.Clamp(i, 0, 1);
flightPathScript.flightSpeed = Mathf.Lerp(incomingFlightSpeed, speed, i);
yield;
}
}
So I call it with.
waypointScript.lerpSpeed(1,(totaFlighpointsDistance/flightSpeed));
In the picture below I've draw a bezier curve and at the last 8 flight points (the red and yellow spheres) I want to start the slow down from the yellow sphere to the last red sphere.
I get the distance in between each of the last 8 flight points and total them up to give me the total distance, I understand to get the time it will take to travel that distance is time = total distance/speed, but as I'm slowing the speed in my function above this will not work.
And because every bezier curve I generate is different, some stretched out, with total distances sometimes ranging from 30 to 8.
So I'm a bit stuck here, thought I'd get this one, but unless I'm missing something simple I can't get my head around it, so any help would be greatly appreciated, thanks.
function lerpSpeed(desiredSpeed : float, overTime : float)
{
var elapsedTime : float = 0;
inco$$anonymous$$gFlightSpeed = flightPathScript.flightSpeed;
while (elapsedTime < overTime )
{
flightPathScript.flightSpeed = $$anonymous$$athf.Lerp(inco$$anonymous$$gFlightSpeed, desiredSpeed, (elapsedTime / overTime));
elapsedTime += Time.deltaTime;
yield;
}
}
@b1gry4n Thanks for the answer, results are showing on a long bezier curve the bot slows down before the end and on a short bezier curve the bot does not seem to slow down, comes to a sudden halt.
Never$$anonymous$$d, I am wrong. One second let me try to wrap my head around this. I completely understand what you are trying to do, the above script simply slows the character down over X time.
@b1gry4b thanks for all this information ..
First let me say that when the bot first flies along the path he slowly accelerates up from 0 up to a speed of 6 or 10 over a period of time (say 3 seconds) depending if the next waypoint, (the end of this bezier curve and the start of the next one) is either higher or lower than him, so if higher a speed of 6 (effect of climbing) and if lower a speed of 10 (effect of descending).
So where does that leave your answer? As he does not fly along at a constant speed.
And I also forgot to say that at a random time a coroutine is called where he will slow down to a speed of 1 slowly rotate to face the player and throw a grenade, then rotate and accelerate back up to speed.
So I think it's not that simple anymore :(
I still think the way I must go is finding the solution to the slow down say over 3 seconds over the last 8 flight positions, or more if needed, as all the rest of the flight works great, just the last bit, the slow down.
Really appreciate your help ..
EDIT .. Just seen you edit about the animation curve, I'll look into that ..
$$anonymous$$ore on the animation curve idea. You could control the start up and slow down with a single curve. Sample the current position in the entire path and evaluate the animation curve. Your curve would end up looking like a bell curve representing the speed of the bot over the course of the entire bezier curve
if youre able to get the last 5 nodes in a path, you surely are able to get a % traveled in the path. animCurve.Evaluate(currentNode/maxnodes)
@b1gry4n Animation curves never used them.
I'm a bit confused you say divide the remaining distance by the max distance and you will get a value between 0.0 and 1.0 but in you code snippet you have ..
float speed = slowDownCurve.Evaluate(currentDistance/maxDistance) * initialSpeed
I've done the two ..
var floatSpeed_0 : float = slowDownCurve.Evaluate(currentDistance/flighpointsOverallDistance) * 6;
var floatSpeed_1 : float = slowDownCurve.Evaluate(flighpointsLeftDistance/flighpointsOverallDistance) * 6;
And below is the output ..
but I can't see how floatSpeed_0 or floatSpeed_1 would be used in a animation curve to decrease the speed!
Thank you very much for taking the time to explain all this in detail, I really do appreciate it.
Now thanks to you I have a better understanding of the power of using animation curves, that could just be what I'm looking for.
Thats my job for today, to nail this flightpath control, I'll keep you updated ..
@b1gry4n Hi,
O$$anonymous$$ I'm liking the animation curve but I see a problem, I'm going with one like in your LIN$$anonymous$$
The problem as you can see in this VIDEO is the acceleration and deceleration is not constant when the distance is changed, is there a way to keep the ends constant no mater the length of the flightpath?
Or would I have to move the second and third points of the cure at runtime depending on the length of the flightpath?
Thanks.
Like I said earlier, If you want time to slow down/speed up, you will need to change speed. Distance is the constant here. You have a set distance at all times, so the speed of the bot needs to dynamically change based off the distance it is traveling if you want him to cover varying distances in the same amount of time. If you want him to reach the end of the path in the same amount of time regardless of the distance between them, a very far distance = higher speeds. A very short distance = lower speeds.
The reason the slowdown/speedup seems inconsistent is because the bot is traveling the same speed. It is actually very consistent, the bot appears to be slowing/speeding up much faster because it is traversing the path at a constant speed. make the distance short and slow the maxspeed, you will see it slows and speeds up.
Answer by b1gry4n · Oct 13, 2016 at 09:36 PM
The code snippet above will give the inverse value. Below I modify it to make reading the curve easier.
Say your total distance of the bezier is 20 units. as you traverse the curve, your position (or distance from the end) in the curve will start to get smaller. It will start at 20 and as you move closer to the end it will be 19, 18, 15, 10, 5, etc. The remaining distance is something you will need to continuously track as you traverse the curve.
For the sake of continuity and clearly reading the animation curve, lets do it like this:
remainingDistance / totalDistance = a value between 0.0 and 1.0.
20/20 = 1
15/20 = .75
10/20 = .5
So now, if we say:
1.0f - (remainingDistance / totalDistance)
we will get the inverse of what we just did. this isnt necessary but it makes reading the animation curve a little easier from left to right. Evaluating the curve with this value will return a modified value based on that curve.
If you were to create a curve like this: http://i.imgur.com/D5EjEck.jpg
you could evaluate the curve with:
animCurve.Evaluate(1.0f - (remainingDistance/totalDistance))
For purposes of explanation, lets say you were 3/4ths the way through your bezier curve. That means if the total distance was 20, your remaining distance would be 5.
1.0f - (5/20) = 0.75f
Now look at the image i linked. At the bottom follow the value over to 0.75, follow it up until it reaches the curve. The returned value will be about 0.62f. Now we take the received value and multiply it by our max speed.
animCurve.Evaluate(1.0f - (distanceRemaining/totalDistance)) * maxSpeed
If the max speed at that time is 100, that means at this point in the curve we are traveling at a top speed of 62. As you can see, as you evaluate along the curve, the fastest you would be moving throughout the entire distance is halfway at 0.5. You can adjust this curve to be how you want. Something like this is what you want I am guessing : http://i.imgur.com/2m6DuiH.jpg
This will automatically slow down and speed up depending on the point you are in the curve. The speed of the character would not matter as you could slow down/speed up and evaluate.
float finalSpeed = animCurve.Evaluate(1.0f - (remainingDistance/totalDistance)) * currentSpeed;
One thing to keep in mind is that if you set the beginning of the curve at a time of 0.0 and a value of 0.0, the returned value will be 0.0. Youll need to set the beginning of the curve to atleast 0.01 or do a check. if(returnedValue == 0) returnedValue = 0.01f
I have created a little demo script. I am creating the curve in the script, but you would want to hand tweak the curve to your desire.
SETUP: create 2 spheres. Place the script on one of the spheres and drag the other sphere into the "target" slot of the script. Press play. Notice how it starts slow, speeds up, and slows towards the end.
using UnityEngine;
using System.Collections;
public class Traverse : $$anonymous$$onoBehaviour {
public Transform target;
public AnimationCurve curve;
public float maxSpeed = 1;
public float currentSpeed;
public float totalDistance;
public float remainingDistance;
Vector3 originalStart;
void Start()
{
target.position = new Vector3(transform.position.x, transform.position.y, transform.position.z + 20);
originalStart = transform.position;
totalDistance = Vector3.Distance(transform.position, target.position);
curve = new AnimationCurve();
curve.Add$$anonymous$$ey(new $$anonymous$$eyframe(0.0f, 0.01f));
curve.Add$$anonymous$$ey(new $$anonymous$$eyframe(0.5f, 1f));
curve.Add$$anonymous$$ey(new $$anonymous$$eyframe(1.0f, 0.0f));
}
void Update()
{
remainingDistance = Vector3.Distance(transform.position, target.position);
if (remainingDistance <= 0.1f)
{
Reset();
return;
}
currentSpeed = curve.Evaluate(1.0f - (remainingDistance / totalDistance)) * maxSpeed;
transform.LookAt(target);
transform.Translate(Vector3.forward * currentSpeed);
}
void Reset()
{
transform.position = originalStart;
}
}
You can change the "maxspeed" value to whatever you want. This would simulate your bot changing speeds throughout its time on the bezier curve. No mater the maxspeed, it will start slow, speed up, and stop slow. Also, while in play mode, mess around with the animation curve itself and look at how it changes the objects speed as it traverses the "path"
If you wanted to get really fancy, you could add keys to a runtime generated animation curve (similar to what I have done in the example) for each node of your bezier curve. Say you have 20 nodes in your curve, you would add 20 keys. The key time would be the currentNode/totalNodes and the key value could be based on the distance between the nodes. If you did it this way, you could control the speed of the object at each node in the curve.
Your answer
Follow this Question
Related Questions
lerp in shader doesn't work as imagined? 1 Answer
Lerp - Time Remaining 1 Answer
Lerp is not moving 2D Prefab over time. 2 Answers
Lerp waypoint path easing 1 Answer
Quaternion.Lerp and Vector3.MoveTowards arent smoothing 1 Answer