Friday, May 17, 2013

Camera Shake

Before we dive in, I recommend you watch the video here.
First up, let's take a look at how the randomized camera shake is implemented:


The shake animation all takes place within a coroutine which allows us to keep our timing variables local to this function as opposed to declaring them for the entire class.  The shake can be configured to last any length of time using the duration variable and this number will be used to determine what percentage of that duration has elapsed (0% to 100% or in this case 0.0 to 1.0).  If you haven't made best friends with math yet I'll do my best to help you visualize it.  Here's what we're doing:



The graph above corresponds to having set a duration of 2.  The x axis represents the time elapsed and the y axis is the percent complete.  The basic equation is percentComplete = timeElapsed / 2.0.  It's important to note that percentComplete is 0 at timeElapsed equal to 0 and percentComplete is equal to 1 at timeElapsed equal to 2.

So now we have a way to determine how far we are through the shake animation.  We care for 2 reasons.  One is we need to know when to stop shaking and the other is that we'll want to gradually fade the shake out (the damper variable) but we'll get back to that later.

Next we want to compute x and y values for how far we should move.  The idea is that our shake is going to be centered around the camera's starting position and when we're done shaking we should be back where we started.  With that in mind the x and y values are just going to be offsets from the camera's original position.

We make that calculation like this:


The Random.value property will give you something between 0 and 1.  It's always a positive number.  Since we're going to be offset from a starting value, we want to be able to offset in either direction which means what we want is a random value that can be negative as well as positive.  So how about -1 to 1.  That's what that equation does for you and its graph looks like this:

So now if you get a random value of 0.5, the value will be remapped to 0.  Now is a good time to explain why we're choosing values that either go from 0 to 1 or -1 to 1.  Let's say that shaking up to a maximum of 1 unit wasn't enough and we wanted to be able to shake as far as 5 units.  By having a value with a maximum of 1, we can just multiply it by what we want (in this case).  This is shown in the code:


But it's also being multiplied by that damper thing too.  Ok, let's cover that.  Since we want to the camera shake to end where it started but we don't want it to pop back afterward, we have to smoothly bring it back.  That's what damper is all about.

For the first part of the shake animation, the damper is intended to do basically nothing.  That shows up in the math when damper is equal to 1 because anything times 1 is itself.  Then we the animation is getting closer to finishing, it gradually starts multiplying the offsets by a number less than 1 until at the very end is multiplies it be 0.  That brings it back to it's original position.  Here's what the graph looks like:

That covers most of what you need to know to understand the other variations.  The main differences are just that the other version using something better than Random to produce the offset values.

You can download the Unity package shown in the video here.  Enjoy!

PS. If you improve upon my code in any way please let me know!  One thing I could think of would be to make the shake more strongly favor a particular direction.  For instance a ball hitting a wall might want to shake more in the direction it was traveling when it hit the wall.