Quick answer: Lerp the camera toward the player without shake, then add shake offset on top. Mixing shake into the lerp target dampens the shake into invisibility.
A boss hits the floor, you trigger a shake by adding random offsets to camera_x and camera_y — but the screen barely wobbles. You crank the shake amplitude to 30 pixels — still nothing. Disable follow and the shake is fine. Re-enable follow and the shake vanishes.
Why Mixing Shake into Lerp Eats the Shake
A common follow pattern looks like this:
/// Camera Step
camera_x = lerp(camera_x, obj_player.x + shake_x, 0.1);
camera_y = lerp(camera_y, obj_player.y + shake_y, 0.1);
Each frame, the lerp moves 10% of the way to the target. A 20-pixel shake_x contributes only 2 pixels to the camera position this frame. Next frame, shake_x is a different random value, so the lerp tries to move toward a new target — never reaching it. The shake is mathematically averaged into noise that approximates the player’s position with mild jitter. Not the snappy shake you wanted.
The Fix: Apply Shake Separately
/// Camera Step
// 1. Smooth follow without shake
follow_x = lerp(follow_x, obj_player.x, 0.1);
follow_y = lerp(follow_y, obj_player.y, 0.1);
// 2. Compute fresh random shake offset
var ox = random_range(-shake_strength, shake_strength);
var oy = random_range(-shake_strength, shake_strength);
// 3. Apply both
camera_set_view_pos(view_camera[0], follow_x - view_w / 2 + ox, follow_y - view_h / 2 + oy);
// 4. Decay shake
shake_strength = max(0, shake_strength - 0.5);
The follow position is lerped smoothly without contamination. The shake offset is added fresh each frame on top of the smoothed position. The lerp never sees the shake values, so it can’t average them away.
Triggering a Shake
/// On boss slam
shake_strength = max(shake_strength, 12); // don’t override an ongoing stronger shake
Using max avoids a small new shake interrupting a strong dying shake. The decay handles fadeout automatically.
Variation: Trauma-Based Shake
Squared trauma (popular in Vlambeer’s blog posts) gives more impactful shakes:
/// trauma is 0…1; shake amplitude scales by trauma^2
var amp = trauma * trauma * MAX_SHAKE;
var ox = random_range(-amp, amp);
var oy = random_range(-amp, amp);
trauma = max(0, trauma - 0.02);
Trauma at 0.5 produces 0.25× shake; at 1.0 it’s full strength. The quadratic curve means the tail of a shake is dramatically less intense than the start — matches how impact feel works psychologically.
Whole-Pixel Snapping for Pixel Art
If your game is pixel art, snap the final position:
camera_set_view_pos(view_camera[0], floor(follow_x - view_w / 2 + ox), floor(follow_y - view_h / 2 + oy));
Without floor, the camera might end up at fractional positions, producing sub-pixel render shifts that look jittery on their own.
Verifying
Trigger the shake while standing still. Verify the camera shakes vigorously and decays smoothly. Now move the player while shaking — the camera should still follow and still shake. If the shake disappears during motion, you’re still mixing into the lerp target.
“Follow then shake. Never follow with shake baked into the target — the lerp will eat your impact.”
The trauma-squared pattern gives the best feel for low effort — copy it once and reuse forever.