Screen shake is a visual effect where the camera shakes, sometimes violently, to create a feeling of impact or chaos. Unless your game is intended to be relaxing, it would probably benefit from some precisely-tuned screen shake.
Screen shake is one of the core pillars of "game juice". "Game juice" refers to all the little details in a game that make it feel fun to play.
If you are interested in learning more about the concept of "game juice", we recommend The Art of Screenshake by Jan Willem Nijman.
Camera Shake in Godot 3.2
This method of implementing camera shake in Godot was created by the YouTuber "Game Endeavor". Watch his video here.
This method is the best because it is modular. It contains all the screen shake logic in a single node, which you can attach to any Camera2D node. Not only that, but is easily customizable, allowing you to create different intensities for different events in your game. And if multiple screen shake events happen in quick succession, this method will ensure the more important events are not overwritten. Read on to learn more.
This solution is designed to be a direct child of a camera node. Add a child to the camera of type Node.
Rename the node to "ScreenShake" and save it as it’s own scene.
Open the ScreenShake scene by clicking the movie clapper icon.
Add a node of type Tween and rename it to "ShakeTween".
A tween node, short for "in-between", smoothly animates a node’s properties over time. We will use the tween node to change the camera’s position to create the screen shake effect. Shaking the camera can be a jarring effect, but the tween will smoothly transition the camera from shaking to still or to shaking at a different intensity.
Next, add two Timer nodes as children of the ScreenShake node. Name one timer "Frequency" and other timer "Duration".
Attach a script to the ScreenShake node.
extends Node const TRANS = Tween.TRANS_SINE const EASE = Tween.EASE_IN_OUT var amplitude = 0 var priority = 0 onready var camera = get_parent() func start(duration = 0.2, frequency = 15, amplitude = 16, priority = 0): if (priority >= self.priority): self.priority = priority self.amplitude = amplitude $Duration.wait_time = duration $Frequency.wait_time = 1 / float(frequency) $Duration.start() $Frequency.start() _new_shake() func _new_shake(): var rand = Vector2() rand.x = rand_range(-amplitude, amplitude) rand.y = rand_range(-amplitude, amplitude) $ShakeTween.interpolate_property(camera, "offset", camera.offset, rand, $Frequency.wait_time, TRANS, EASE) $ShakeTween.start() func _reset(): $ShakeTween.interpolate_property(camera, "offset", camera.offset, Vector2(), $Frequency.wait_time, TRANS, EASE) $ShakeTween.start() priority = 0
To start a screen shake, you will want to call the "start" function. The "duration" is how long the effect will last in seconds. The "frequency" is how many camera times per second the camera will change direction. The "amplitude" is far from center the camera will move. You can also set the "priority" of the effect. A higher priority effect will not be overwritten by a low priority effect. Big explosions will continue uninterupted by smaller explosions.
Now let’s connect the two timers to this script.
Select the Frequency node. Select the "Node" tab on the Inspector window. Make sure you are on the "Signals" section. Double-click the "timeout()" signal. Connect it to the ScreenShake script.
func _on_Frequency_timeout() -> void: _new_shake()
Now let’s to the same for the Duration timer. Double-click it’s timeout signal and connect it to the ScreenShake node.
func _on_Duration_timeout() -> void: _reset() $Frequency.stop()
Now that ScreenShake node is set up, you can attach a script to the Camera. You can define functions to start the screen shake effect with preset values.
extends Camera2D func small_shake -> void: $ScreenShake.start(0.1, 15, 4, 0)