How to create a 2D camera shake in Unity/C#

Let’s see how to shake things up by moving the camera when the player takes a hit!

This article is also available on Medium.

A while ago, I shared a game dev log of how I made a basic arcade game called The Escape. In this small-sized Unity/C# game, you have to escape with your spaceship by avoiding the walls and the lasers and by grabbing as many coins as possible. There are even magnets that temporarily change your course, and a shop to buy upgrades between each run.

Here: check out the little demo 😉

By the way, if you want, you can play the game over here!

https://minapecheux.com/games/the-escape

In this game, there are lots of little mechanics at play to give the players feedback on their actions and to have better immersion. One in particular is the camera shake that happens whenever your ship collides with a wall or a laser:

As you can see, the effect happens whenever I get hit by a laser or I crash into a wall (if I have some energy left!).

And this is actually pretty quick to create – so, today, let’s how we can create such a camera shake effect for a 2D camera!

The camera setup

First things first: here, I’m using an orthographic camera that is looking at the scene from the side (i.e. its forward axis is orthogonal to the plane of the game):

Also, the camera in itself doesn’t move while I play, it’s the walls that “keep coming” towards my ship, and then are “re-spawned” (using object pooling) at the other end whenever they get past my position:

All this means that, basically, my camera shake will just be a little update of my camera’s position over a short period of time, in the X and Y axes…

The C# code

Ok – that’s actually pretty easy to do!

Here, I’ll simplify things and focus on the camera shake logic; so let’s say we want the camera to shake whenever we press the left-mouse button.

To begin with, let’s make sure we have a reference to our camera and that we cache this reference:

This is important because the Camera.main built-in accessor is actually not optimised, and it needs to go through a list of objects to find the camera each time you call it… and since we are going to move the camera during several frames, it would be a shame to have to re-find it every time! 😉

Now, because we want to perform a bit of logic over some time, we need to make sure that this process doesn’t collide with the main loop of the game. In other words, we want to avoid the screen from completely freezing while our “camera shake logic” is running – which would obviously be pretty bad! The solution here is to make use of Unity coroutines. Roughly put, those are special functions that allow you to run some code parallel to the main process and therefore run multiple pieces of logic at the same time.

But, in computers, you can’t actually have two things in parallel. Because of the way processors are built, everything is intrinsically sequential. The trick we can use, however, is to simulate parallelisation by constantly switching between the two processes; by doing just a little bit of work here, and then a little bit of work there, the computer is happy because they were actually executed one after the other, but the switch was so fast we as human users feel like the two little steps were done at the same time!

The question is: how do you “cut down” work like this? Usually, C# code is executed all at once: if I call a function, then it will run all of its instructions before exiting, right?

Well – the answer is to use IEnumerators. This is a special object that can be queried, then left on its own for a while, and then queried again, and then continue to live its life, and then get queried again, etc. And so, a Unity coroutine is simply a C# function that returns an IEnumerator object. This way, the program can regularly “enter and step” the coroutine to have it run seemingly in parallel of the main loop.

Here is the C# code setup:

In my Update() method, I check to see if I’m left-clicking. If I am, then I start my shake coroutine with Unity’s built-in StartCoroutine() method. Note that this function is only available inside a class that inherits from the MonoBehaviour class!

At that point, the second process starts running and regularly steps through its logic. Each step lasts one frame: this is determined by the yield return null instruction that creates an IEnumerator which yields every Unity frame.

Now, at the moment, this code will keep on running the coroutine forever, because I’m using an infinite while loop. But, in truth, I want the camera shake to last for a given amount of seconds, for example 0.35 seconds in The Escape. To do this, all we need to do is add a time counter and increase it by the time delta between our current frame and the previous one – this is automatically stored in Unity’s Time.deltaTime variable, and it matches the yield return null from before:

The next step is to make sure we store somewhere our initial position so that, when the shake is done, we can reset to this starting point:

And finally, inside our loop, we will shake our camera by computing a random position around the starting point (and we know that the camera is at the origin, so we want X and Y to be random floats around zero) and applying it to the camera:

Note: the magnitude variable allows me to better adjust how much the camera moves during the shake 😉

And tadaa: with this simple coroutine, we can now shake our camera whenever we left-click the mouse 🙂

Bonus: avoiding multiple shakes, optimising the computation

For now, if you left-click again while the camera is moving, you will start to stack multiple coroutines on top of each other and the camera will get a bit crazy. To avoid this, we can use a little boolean flag in our class to check we are not already running a coroutine, and abort the start of a new coroutine if it’s true:

Finally, a nice thing with coroutines is that you can actually choose how “frequently” they are run: since our yield instruction determines the exit points and the moments we can step to the next instruction in the coroutine, it also determines how often the code is run.

This is why, sometimes, to optimise our code, we can use coroutines: if you have some logic that needs not be run every frame, you can move it from the Update() into a coroutine, and then inside this coroutine use a custom “frequency” to lighten the load:

Here, for example, I’m only running my camera position update every 0.05 second (which is greater than the usual timeDelta), and so I’m basically asking a bit less from my processor. Of course, as with all optimisations, it is a tradeoff between efficiency and effect, so you absolutely have to insure this kind of optimisation doesn’t hinder your gameplay or visuals 😉

Conclusion

Today, we saw how we can use Unity coroutines to quickly create a camera shake effect in 2D, which helps give the players feedback and immerse them in the action!

I hope you liked this quick tutorial – as usual, thanks a lot for reading and feel free to share your ideas for other Unity tutorials in the comments 🙂

Leave a Reply

Your email address will not be published.