- Home /
Ramping animation speed
I'm trying to ramp up the speed of a fan from 0 to 1.0 animation speed. I have a script that begins the animation playback and I thought using a Mathf.SmoothDamp would do it, but it just gives me really slow playback. Script is below - anyone have any thoughts as to another way of doing this?
(for clarity, I've omitted the code for the StopFan() function, since it doesn't affect this issue)
var fanStart : float = 0.0;
var fanEnd : float = 5.0;
var smoothTime : float = 2.0;
var velChange : float = 0.0;
private var clicked : boolean = false;
private var switchMe : GameObject;
switchMe = GameObject.Find("finalSwitch");
private var fan : GameObject;
fan = GameObject.Find("fanPivot");
private var fpsCharacter : GameObject;
fpsCharacter = GameObject.Find("Graphics");
function OnMouseUp()
{
if(clicked)
{
StopFan();
}
else if (!clicked)
{
StartFan();
}
}
function StartFan()
{
animation["switchedOn"].speed = 1.0;
animation.Play();
audio.Play();
var rampUpSpeed : float = Mathf.SmoothDamp(fanStart,fanEnd,velChange,smoothTime);
fan.animation["fanRotation"].speed = rampUpSpeed;
fan.animation.Play();
fan.audio.Play();
clicked = true;
}
Answer by aldonaletto · Feb 09, 2012 at 01:12 AM
You must create a routine with a loop that counts time from 0 to the desired ramp duration in seconds, and use Mathf.Lerp(fanStart, fanEnd, time/duration) to calculate the fan speed at each iteration.
To let Unity work while you're counting time, insert a simple yield in the loop, what makes the function a coroutine. Coroutines run in the background: they stop at the yield instruction and let Unity free till the next update cycle, when the coroutine execution is automatically resumed right after the yield.
function StartFan(){
animation["switchedOn"].speed = 1.0;
animation.Play();
audio.Play();
RampUpSpeed(10.0); // start the coroutine RampUpSpeed with 10 seconds ramp duration
fan.animation.Play();
fan.audio.Play();
clicked = true;
}
function RampUpSpeed(duration: float){
var t: float = 0;
while (t < duration){ // loop during "duration" seconds:
t += Time.deltaTime; // count time...
// and set speed from fanStart to fanEnd proportionally to time/duration:
fan.animation["fanRotation"].speed = Mathf.Lerp(fanStart, fanEnd, t/duration);
yield; // let Unity free till next update cycle
}
}
NOTE: If the fan sound is constant and loopable, you can even set its frequency proportional to the speed - just add the line below right before the yield instruction:
fan.audio.pitch = t/duration;
Holy cow! That did it! Thanks so much for taking the trouble. And the audio pitch change was gravy. It was a simple solution, but it just kept eluding me. Thanks again!
An additional note: since the coroutine runs automatically in the background, make sure that you only call StartFan once for each fan - if called multiple times, multiple RampUpSpeed coroutines start to run, what may produce weird results, and even slow down or crash the game.
Does the coroutine finish its run after the "yield" statement, or is there something else I should do to clear it from memory?
Also, your comment raised another question - if I wanted to turn the fan off and thus slowly come to a stop, would I do something like a RampDownSpeed function, or would that feed into the potential issue you mentioned? Thanks!
The coroutine frees the allocated memory automatically upon return (after the loop has ended, in this case) - you don't need to do anything else.
To ramp down, you must make sure the first coroutine has ended before starting your RampDownSpeed function. Coroutines are resumed each update cycle right after all Update functions were called. If you start RampDownSpeed while RampUpSpeed has not finished, the one executed last will "hide" the other (both modify the animation speed, but only the change did last will take effect)
That's what I guessed - thanks for confir$$anonymous$$g it for me. Right now, it's all working beautifully, and I sincerely appreciate your generous suggestions and feedback!
Answer by tingham · Feb 07, 2012 at 02:58 AM
Your fanStart value isn't being updated to the current speed value (the result of the lerp/smooth damp so your constant value for T just returns the same value during each iteration.
// C#
float currentSpeed = 0f;
float finalSpeed = 1f;
void Update () {
animation["fanRotation"].speed = currentSpeed;
}
IEnumerator RampFanSpeed () {
while (currentSpeed < finalSpeed) {
currentSpeed = Mathf.Lerp(currentSpeed, finalSpeed, 0.25f);
}
}
Yes -- need to call SmoothDamp every frame until rampUpSpeed is done, and the time parm is messed up.
Lerp requires an increasing number from 0 to 1. So, Time.deltaTime (always around 0.02) doesn't work for Lerp, but is great for SmoothDamp.
I'm having a hard time figuring out how this would work in a coroutine. $$anonymous$$gestions?
Your answer
Follow this Question
Related Questions
Mathf.Smoothdamp, need help troubleshooting! 0 Answers
Animated Billboard or Animated Model? 2 Answers
Handling Animation and movement speed 0 Answers
How to calculate speed without rigid body 0 Answers
Time goes wrong in the Build 1 Answer