Additive 2D Camera Shake - For overlapping shakes in rapid succession

Hi Folks!

New around these parts, so apologies if this isn’t the right place for this. It felt like the most suitable home.

I created a brief script for additive 2d camera shake (when you have multiple shakes overlapping and you want them to combine to extend the shake and increase it’s magnitude) that I wanted to share so someone looking for it in the future might find it. Hopefully this is helpful for someone! :slight_smile:

class_name ShakeableCamera extends Camera2D


var shaking := false
var remaining_time : float = 0
var elapsed_time : float = 0

#strength controlls the overall magnitude of the shake
#while smoothness controlls how smooth motion is, kind of "anti-strength"

var smoothness :float = 0.5 #0-1, higher values smooth out the shake motion more so that it's less jarring
var current_strength :float = 0

func rand_offset_from_strength()-> Vector2:
	var vec = Vector2()
	vec.x = randf_range(-current_strength, current_strength)
	vec.y = randf_range(-current_strength, current_strength)
	return vec

func shake(time:float, strength: float):
	
	#If the camera is already shaking, then
		#reset the elapsed time and remaining time of the shake
		#boost the strength of the shake, so that shakes have an additive effect
	remaining_time = time
	current_strength += strength 
	elapsed_time = 0.0
	
	
	var offset_position := Vector2(0,0)
	var offset_rotation = 0
	
	#If shakes overlap, any subsequent call only effects the shake by changing
	#the variables. The first call handles the actual shaking.
	if not shaking:
		shaking = true
		while elapsed_time < remaining_time:
			
			#gradually decay the strength
			current_strength = lerpf(current_strength, 0, elapsed_time/remaining_time)
			
			#smooth motion in the offset between random values
			offset_position = offset_position.lerp(rand_offset_from_strength(), 1-smoothness)
			
			#lerp back towards zero offset over time
			offset_position = offset_position.lerp(Vector2(0,0), elapsed_time/remaining_time)
			offset = offset_position
			
			#if you want to add rotation to the shake, uncomment the line below 
			#rotation = lerpf(randf_range(deg_to_rad(0),deg_to_rad(0)),0, elapsed_time/remaining_time)
			
			elapsed_time += get_process_delta_time()
			await get_tree().process_frame
			
		shaking = false

1 Like

Thanks, i’ll credit you in my game for the GMTK 2026 jam

Thanks, good luck with your submission! I was really hoping to participate this year but I’ve had too much going on lately, so it’s nice to feel like I’ll be involved in some way.

Thanks, i’ll also credit you in my game for the GMTK 2026 jam!