Get the FULL version

Unity: Slow Motion and Rigidbody behavior

Unity: Slow Motion and Rigidbody behavior thumbnail

It’s been awhile since the last Unity post, in fact, it’s been quite some time since there’s something new on the website. I want apologize to all the 41 Post readers for taking so long to put together a new tutorial. So, let’s get to the tutorial.

This post explains how to set the parameters found at Unity’s Time class to make the game run in slow motion (also known as “bullet time”). It’s important to note that the following code was created for Unity3D 3.4, thus, the code featured below might work different in other Unity versions.

The concept behind the code is simple: just set the Time.timeScale parameter in a range between 0 and 1. This logic can be found at the official documentation, and it works quite well for all the code placed inside the Update() method. This attribute affects all other time attributes from the Time class. Eg.: a value of 0.25f will make time pass four times slower than normal.

By making time go slower, the objects with the Rigidbody component will start to display two problems: their physical simulation won’t behave the same while the time is passing slowly and their movement will appear to skip some frames (their animation will be “choppy”). To solve these to problems, just look at the following code that set’s the game in “bullet time” after pressing the Fire1 button:

using UnityEngine;
using System.Collections;

public class SlowDown : MonoBehaviour
{
    //the factor used to slow down time
    private float slowFactor = 4f;
    //the new time scale
    private float newTimeScale;

    // Called when this script starts
    void Start()
    {
        //calculate the new time scale
        newTimeScale = Time.timeScale/slowFactor;
    }

    // Update is called once per frame
    void Update ()
    {
        //when "Fire1" is pressed
        if (Input.GetButtonDown("Fire1"))
        {
            //if the game is running normally
            if (Time.timeScale == 1.0f)
            {
                //assign the 'newTimeScale' to the current 'timeScale'
                Time.timeScale = newTimeScale;
                //proportionally reduce the 'fixedDeltaTime', so that the Rigidbody simulation can react correctly
                Time.fixedDeltaTime = Time.fixedDeltaTime/slowFactor;
                //The maximum amount of time of a single frame
                Time.maximumDeltaTime = Time.maximumDeltaTime/slowFactor;
            }
            else if (Time.timeScale == newTimeScale) //the game is running in slow motion
            {
                //reset the values
                Time.timeScale = 1.0f;
                Time.fixedDeltaTime = Time.fixedDeltaTime*slowFactor;
                Time.maximumDeltaTime = Time.maximumDeltaTime*slowFactor;
            }
        }
    }
}

The code above works by declaring two variables: one to define how much the time will be slowed down (line 7) and the other one to store the new time scale (line 9). Next, there is the Start() method, that calculates the new time scale, and store’s it at the newTimeScale attribute (line 12 through 16). That way, it will be not necessary to calculate how much the time is being slowed down again.

Then, there’s the Update() method, which will check if the Fire1 button has been pressed (line 22). Case that’s true, there’s another if statement inside this block that checks if the current time scale is equal to 1, thus making sure that the game is running normally, so that the time can be set to slow motion (line 25).

Finally, if the above is also true, the timeScale is assigned to the same value as the newTimeScale, making all the code placed inside the Update() methods on the scripts run in slow motion (line 28). Then, the Time.fixedDeltaTime attribute is proportionally reduced by the same amount as Time.timeScale (line 30), ensuring that the Rigidbody simulation runs smoothly. Removing this line will make the Rigidbody objects’ movement appear to be “choppy” while the game is running at a reduced time scale.

Furthermore, Time.maximumDeltaTime is scaled just like the Time.fixedDeltaTime: dividing it by slowFactor (line 32). By doing so, the physics simulation when the game time is running slowly will be almost the same as when it is running normally. If this line is removed, it will be easy to notice that the behavior of the rigid bodies are going to be very different from when the game time is at normal speed.

Lastly, the else if block resets the values to it’s defaults when the Fire1 button is pressed and the game is in slow motion (lines 34 through 40).

That’s it! It’s important to notice that even if we make these adjustments to the Time class attributes, there is no way to guarantee that the physics simulation will be exactly the same as when the game is running in slow motion. The above code just achieves an approximation of what it would be the expected simulation. Additionally, when the time is changed at the middle of the physics simulation, the rigid bodies will behave in a different manner, so it’s best to change the timeScale value when the rigid bodies are sleeping and/or not colliding with anything.

Another thing its possible to do is to reverse time by assigning a negative value to Time.timeScale attribute. However, the physics simulation and code placed inside the FixedUpdate() method aren’t going to work, because timeScale will affect the Time.fixedDeltaTime and the Time.fixedTimeStep values, that aren’t allowed by Unity to be smaller than zero.

Here’s an example project with everything that was explained here:

4 Comments to “Unity: Slow Motion and Rigidbody behavior”

  1. Richard says:

    Thanks a lot, I was having the Timescale x Physics issue and I didn’t know how to solve it. You made my day! Now I have a decent slow motion effect in my FPS game. Thanks again.

  2. Thanks for this post. I used your code in my pool game, Pool with Friends on iOS.

  3. Jordan says:

    Thanks so much for this. Really a simple fix that I never thought of. Makes my slomo 10 times better… and (.1 times the normal speed :P).

Leave a Reply to Richard

Post Comments RSS