Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

Lerp over Time.timeScale

Discussion in 'Scripting' started by ThomasUnity, Nov 15, 2015.

  1. ThomasUnity

    ThomasUnity

    Joined:
    Jul 10, 2015
    Posts:
    17
    Hi,
    I want my 'game' to slow down after the player falls. But with my code, the Lerp takes place in 1 frame, when i pause the movie and play it frame by frame. So the movie does not slow down gradualy, but at once. And the console suddenly shows all the Logs I asked for after 1 next frame.
    I tried to slow down gradualy bij using a for loop and Lerp between 1 and 0.1. Why doesn't my code act over a number of frames?

    if (offscreen){
    if(gameObject.transform.tag == "Player"){
    Debug.Log("Player Falls");

    for(var t:float = 0f; t < 1; t += Time.deltaTime /5){
    Debug.Log("Lerp: " + t);
    Time.timeScale = Mathf.Lerp(1.0, 0.1, t);
    Debug.Log("TimeScale: " + Time.timeScale);
    }
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,744
    It doesn't act over a number of frames because you aren't using a coroutine.

    If this code is in its own function (e.g. not in Update), all you need to do is add 'yield' inside the for loop.

    However, there's one thing you should note. As Time.timeScale slows, Time.deltaTime will get smaller and smaller - what looks like a 5 second process will probably actually take ~25 seconds to execute. (if you'd made it lerp down to 0, it would probably never finish!) Instead, use .realDeltaTime, which is unaffected by timeScale.
     
  3. ThomasUnity

    ThomasUnity

    Joined:
    Jul 10, 2015
    Posts:
    17
    Thanks!
    I am writing code in javascript and i believe javascript doesn't have coroutines. So the code is in its own function. I added a "yield WaitForSeconds(Time.realDeltaTime);" But it throws an error: realDeltaTime is not a member of 'UnityEngine.Time'.
    When i use a yield with the regular deltaTime, it doesn't do the whole for-loop at once anymore, which is good, but everything goes very jittery.
     
  4. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,744
    Incorrect. Javascript has coroutines; you couldn't use 'yield' without them. They're just implicit. Javascript has a special case where, if it sees a yield statement in a function, it assumes you want a coroutine. (In C#, you'd have to make the function return IEnumerator instead of void)

    Oh, the error is my bad. I meant to say Time.unscaledDeltaTime.

    However, don't do that. The unscaledDeltaTime goes in the declaration of your for loop (replacing Tiem.deltaTime), not in the body. Just put "yield;" by itself. In JS, this makes it yield one frame, which is what you want here. (In C#, you'd use "yield return null;" to accomplish the same)
     
    Last edited: Nov 16, 2015
    Kiwasi likes this.
  5. ThomasUnity

    ThomasUnity

    Joined:
    Jul 10, 2015
    Posts:
    17
    Great! Thanks a lot. The unscaledTime was new to me. And the yield does solve the issue. Great to know how to translate the C# examples using coroutines.
    One more question: now that the timescale decreases, so does the framerate. At the end of the slowing down, i see 1 frame change per second.
    Is it possible to increase the framerate while the timescale goes down? That would make the motion go very smooth.

    here's my working script so far:

    function SlowDown(){
    for(var t:float = 0f; t<=1 ; t += Time.deltaTime/2){
    Time.timeScale = Mathf.Lerp(1.00, 0.00, t);
    Debug.Log(Time.timeScale);
    if(Time.timeScale <= 0.05){Time.timeScale = 0;}
    yield;
    }
    }
     
  6. ThomasUnity

    ThomasUnity

    Joined:
    Jul 10, 2015
    Posts:
    17
    I made a little test trying to multiply the framerate by 5 and deviding the timescale by 5, but in the animation it seems there are still the same number of frames, only displayed with longer intervals. It goes jittery.
    How to slow down, but also keep a smooth motion?

    public var tempo:float = 0.2;

    function Awake(){
    Application.targetFrameRate = 300;
    }

    function Start () {
    Time.timeScale = tempo;
    }
     
  7. ThomasUnity

    ThomasUnity

    Joined:
    Jul 10, 2015
    Posts:
    17
    I enabled Interpolate on the rigidbodys. Now it's smooth.
     
  8. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,744
    The "framerate" you were seeing is the physics timestep. The actual framerate was still the same, just physics was only updating at its same time scale as before. It's like you're taking a 600fps slow-mo video of a film - the film's still running at 24 fps.

    You can solve this with interpolate, but you may notice that collisions and such will be a lot less responsive. You can change the physics timestep by setting Time.fixedDeltaTime. A good setting would be 0.02 * Time.timeScale - this will keep the physics moving at what appears to be 50fps, just like they do when time is unscaled. (Be careful to set the fixedDeltaTime back to 0.02ish when you resume normal time, otherwise the game will be trying to calculate hundreds of physics frames every visual frame, and the game will slow to a crawl!)
     
    Last edited: Nov 16, 2015
  9. ThomasUnity

    ThomasUnity

    Joined:
    Jul 10, 2015
    Posts:
    17
    you're the best! Thanks.