Bullet Time Effects in Unity

Marcos Germano
Runtime Revolution
Published in
6 min readAug 7, 2018

--

Photo by Jordan Benton from Pexels

A small introduction to bullet time effects

Have you ever wondered how game developers and even motion picture directors add slow motion effects to their products and/or movies?

It’s simple, they just play around with the flow of time. Wait…does this still sound complicated?

If so, keep reading this blog post to know more about how you can implement this effect in a Unity game or application. I promise to keep it simple, but first, I’ll give you an introduction to the theme.

The reason I mention “Bullet time” instead of “Slow motion”, is because these slow down effects were first memorably used in the original Matrix film, back in 1999, which was both considered a great moment in the cinema industry as well as a big advancement in the development of special effects. They used a new technology to capture a scene in 360º while, at the same time, applying a slow motion effect to the environment, in order to create the illusion that the characters could move (much) faster than the speed of bullets and other objects travelling at them.

The basics in Unity

First, we’ll need to create/open a project that has the standard assets offered by Unity. While installing Unity, you will be prompted to install the Standard Assets Project, to which you should choose yes. If you didn’t, that is not an issue. You will just have to create a player asset by yourself (instead of importing the first-person player asset from the project provided by Unity).

Alas, once the player asset is added to your project, you need to create a new scene (basically think of a scene as a level in your game, or a part of a level). Afterwards, you add the player asset to your scene by dragging it directly into the scene panel.

Now you should be ready to move on to “stage 2” of this Unity tutorial: creating an ExplosionGun script, that you will use to trigger explosions. Later on, you’ll work on another script to apply a slow motion effect to the environment whenever an explosion occurs.

In a Unity game, you can add any number of scripts to objects (you can use C# or JavaScript to create these, but in this post I’ll be focusing only on C#).

In your ExplosionGun script, it is going to be necessary to track mouse clicks (or any other key, if preferred), and cause it to shoot when the chosen key is pressed. In order to do this, you should override the Update method of the ExplosionGun, that is used quite frequently to update its state.

Now let’s implement the Shoot method. For this, we’ll use a technique called Raycasting, which basically means shooting a ray from the player’s point of view, in a specific direction. This may seem complicated, but Unity makes it fairly simple.

We just need to provide the player’s position and the direction we’re looking at, and see if the ray we’re shooting collides with something. If it does, then we instantiate our explosion and, later on, apply our slow motion effect.

The Standard Assets Project also contains a basic explosion asset, that you can use as the asset to instantiate when we shoot something.

The Shoot method should look something like this:

Ok, you’ve created the gun, but it doesn’t do anything “fancy” yet, besides spawning explosions…so, it’s time to move towards our next goal!

The crux of Bullet Time effects in Unity

Let’s continue by adding an empty object to your scene, which is going to act as our TimeFlowManager, to “control” the flow of time.

First things first, you’ll have to add two float number variables: the slowdownFactor and the slowdownLength. The first one represents how much we want to slow down time, while the second one represents for how long we will be slowing it down. So if you want to slow down the time for 2 seconds, then you’ll need slowdownLength = 2.0f.

So, now you need to implement the method which will actually apply the slow motion effect. To do so, you need modify the global variable timeScale from Unity’s Time singleton class. The timeScale defines how fast time flows: if it’s equal to 1, time flows in normally, if it’s higher than 1, it speeds up and if it’s below 1…well, you guessed right, it slows down.

With this you can implement the following line in your method that, for the sake of simplicity, will be called DoSlowMotion:

Now imagine you set your slowdownFactor variable to 0.05. The way the time scale works is dividing 1 by your factor; this means that you will be making time 20 times slower than usual. Cool!

However, this alone is not enough.

Objects in Unity are updated each time a frame is rendered (usually many, many times per second), but the physics of the objects in Unity are managed by another method: the FixedUpdate.

Normally, this method runs 50 times per second, regardless of the processing power of you CPU and the load it is under, meaning that once you slow down time, every object will be slowed, yet the period between render updates will remain the same because you did not change the rate of updating. This will give you the perception that the scene is “lagging”.

In order to fix this problem you need to update another global Time variable: the fixedDeltaTime. Since the frequency of fixed updates is usually 50, it means that the fixedDeltaTime is by default 1 / 50 = 0.02. Therefore, you have to multiply fixedDeltaTime by your timeScale, to make the fixed updates run more often while time is slowed down.

Right now, your DoSlowMotion method should look like this:

If you try out your game now, the slow down effect will look a lot smoother than before. But…we’re not done here. Once the slow down effect is applied, your game will never return to normal, because you did not implement a way to regress back to the real flow of time.

Alright then, let’s go ahead and add the Update method to our TimeFlowManager (in reality we will be overriding the Update method of our object, the one which runs many, many times a second).

This is where your slowDownLength variable comes in. Every time a frame is rendered, you increment the timeScale by 1/slowDownLength.

Your Update method should now be as follows:

Eventually, after 2 seconds have passed (if this is the value that you gave your slowDownLength), your game should have returned to normal…but did it?

If you were paying attention, I mentioned that the Update method is executed several times per second, which means that, after just a fraction of a second, your game will not only have returned to normal, but also have been sped up a ton. In order to fix this, you will need to multiply your increment by Time.deltaTime. This will force the timeScale to be restored in the period of 2 real time seconds. Oh, and be sure to clamp the value of the time scale between 0 and 1, in order to avoid the game speeding up above normal (unless you want it to).

Right now, your Update function should look like this:

However, if you test your game right now, you may notice that once the slow motion is applied, the movement of the slowed objects will return to normal at an exponential rate (slow at the start, fast at the end); we can fix this by modifying our Update function as follows:

By multiplying our value (1.0 / slowdownLength) by Time.unscaledDeltaTime (the amount of real time that has passed since the last Update method call, not affected by the changes in the timeScale), we make sure that we only add back a fraction of the timeScale per update. Eventually, after 2 seconds in real time, the game correctly returns back to normal.

Conclusion

And this is it. You have now mastered part of the flow of time in Unity. Feel free to apply this effect as you wish! I leave you here with a couple of challenges that could perhaps be of your interest:

  • After learning what you have, how would you make time stop? (Medium)
  • How could you potentially rewind time? (Hard)

I work as a full-stack developer at Runtime Revolution, where we focus on developing the best solutions for our clients’ problems.

I’m also somewhat of a computer geek and game “afficcionado”, both of which lead me to reading and being up-to-date with the latest news in the world of technology and gaming.

--

--