This example showcases how to implement 2D screen shake. It follows the GDC talk "Math for Game Programmers: Juicing Your Cameras With Math" by Squirrel Eiserloh
The key features are:
- Camera shake is dependent on a "trauma" value between 0.0 and 1.0. The more trauma, the stronger the shake.
- Trauma automatically decays over time.
- The camera shake will always only affect the camera
Transformup to a maximum displacement. - The camera's
Transformis only affected by the shake for the rendering. TheTransformstays "normal" for the rest of the game logic. - All displacements are governed by a noise function, guaranteeing that the shake is smooth and continuous. This means that the camera won't jump around wildly.
Controls
| Key Binding | Action |
|---|---|
| Space (pressed repeatedly) | Increase camera trauma |
use ;
// Before we implement the code, let's quickly introduce the underlying constants.
// They are later encoded in a `CameraShakeConfig` component, but introduced here so we can easily tweak them.
// Try playing around with them and see how the shake behaves!
/// The trauma decay rate controls how quickly the trauma decays.
/// 0.5 means that a full trauma of 1.0 will decay to 0.0 in 2 seconds.
const TRAUMA_DECAY_PER_SECOND: f32 = 0.5;
/// The trauma exponent controls how the trauma affects the shake.
/// Camera shakes don't feel punchy when they go up linearly, so we use an exponent of 2.0.
/// The higher the exponent, the more abrupt is the transition between no shake and full shake.
const TRAUMA_EXPONENT: f32 = 2.0;
/// The maximum angle the camera can rotate on full trauma.
/// 10.0 degrees is a somewhat high but still reasonable shake. Try bigger values for something more silly and wiggly.
const MAX_ANGLE: f32 = 10.0_f32.to_radians;
/// The maximum translation the camera will move on full trauma in both the x and y directions.
/// 20.0 px is a low enough displacement to not be distracting. Try higher values for an effect that looks like the camera is wandering around.
const MAX_TRANSLATION: f32 = 20.0;
/// How much we are traversing the noise function in arbitrary units per second.
/// This dictates how fast the camera shakes.
/// 20.0 is a fairly fast shake. Try lower values for a more dreamy effect.
const NOISE_SPEED: f32 = 20.0;
/// How much trauma we add per press of the space key.
/// A value of 1.0 would mean that a single press would result in a maximum trauma, i.e. 1.0.
const TRAUMA_PER_PRESS: f32 = 0.4;
/// Let's start with the core mechanic: how do we shake the camera?
/// This system runs right at the end of the frame, so that we can sneak in the shake effect before rendering kicks in.
/// Increase the trauma when the space key is pressed.
/// Restore the camera's transform to its unshaken state.
/// Runs at the start of the frame, so that gameplay logic doesn't need to care about camera shake.
/// The current state of the camera shake that is updated every frame.
/// Configuration for the camera shake.
/// See the constants at the top of the file for some good default values and detailed explanations.
/// Spawn a scene so we have something to look at.
/// Tiny 1D Perlin noise implementation. The mathematical details are not important here.