![]() |
Attention | Topic was automatically imported from the old Question2Answer platform. |
![]() |
Asked By | Hammer Bro. |
![]() |
Old Version | Published before Godot 3 was released. |
I couldn’t find a built in screen-shake function, so I implemented the first bit o’ logic I found on the internet. Since it’s a pretty common feature in games these days, I figured I’d share it. Major features include:
- Variable duration, frequency, and amplitude.
- Maintains its own offset so it can be used in combination with other effects.
Since it extends Camera2D, all you have to do to use it is to instance this script instead of base Camera2D then call the shake function. I find that setting the duration, frequency, and amplitude to 0.2, 15, and 8 respectively gives a nice light shaking effect.
extends Camera2D
var _duration = 0.0
var _period_in_ms = 0.0
var _amplitude = 0.0
var _timer = 0.0
var _last_shook_timer = 0
var _previous_x = 0.0
var _previous_y = 0.0
var _last_offset = Vector2(0, 0)
func _ready():
set_process(true)
# Shake with decreasing intensity while there's time remaining.
func _process(delta):
# Only shake when there's shake time remaining.
if _timer == 0:
return
# Only shake on certain frames.
_last_shook_timer = _last_shook_timer + delta
# Be mathematically correct in the face of lag; usually only happens once.
while _last_shook_timer >= _period_in_ms:
_last_shook_timer = _last_shook_timer - _period_in_ms
# Lerp between [amplitude] and 0.0 intensity based on remaining shake time.
var intensity = _amplitude * (1 - ((_duration - _timer) / _duration))
# Noise calculation logic from http://jonny.morrill.me/blog/view/14
var new_x = rand_range(-1.0, 1.0)
var x_component = intensity * (_previous_x + (delta * (new_x - _previous_x)))
var new_y = rand_range(-1.0, 1.0)
var y_component = intensity * (_previous_y + (delta * (new_y - _previous_y)))
_previous_x = new_x
_previous_y = new_y
# Track how much we've moved the offset, as opposed to other effects.
var new_offset = Vector2(x_component, y_component)
set_offset(get_offset() - _last_offset + new_offset)
_last_offset = new_offset
# Reset the offset when we're done shaking.
_timer = _timer - delta
if _timer <= 0:
_timer = 0
set_offset(get_offset() - _last_offset)
# Kick off a new screenshake effect.
func shake(duration, frequency, amplitude):
# Initialize variables.
_duration = duration
_timer = duration
_period_in_ms = 1.0 / frequency
_amplitude = amplitude
_previous_x = rand_range(-1.0, 1.0)
_previous_y = rand_range(-1.0, 1.0)
# Reset previous offset, if any.
set_offset(get_offset() - _last_offset)
_last_offset = Vector2(0, 0)
Bookmarked! I’ll try it later. Thanks for posting!
ugly_cat | 2016-03-02 00:18
I’ve evolved this script for 3d camera.
Shake 3D camera script (Godot Engine 2.1)
vctr | 2017-12-06 14:22
@vctr
Cool! Nice to see some 3D scripts passing around. I’m not that good yet at programming (in Godot), so this is welcome.
But how do I implement your script? Because I already have a camera script attached to my camera, to follow the car dynamically (base-script by Bastiaan Olij tutorial).
Since you can’t attacht 2 scripts to 1 node, do I just copy your script and paste it with what I already have?
The function _process() doesn’t kick in untill you use the function shake() somewhere, right?
Edit: maybe I found it. Is it possible that instead of using extends Camera I could use extends “res:://path/to/mainScriptCamera.gd” ??
Edit 2: still can’t seem to get this to work. First edit doesn’t work I guess, since the script then becomes the child of the script and I’m not able to call a function of that child (or maybe I’m doing it wrong?).
Now tried it with
var camExtScript = preload("res://Scripts/cam_Shake.gd").new()
in the main camera script at the top (set the shake script back to extends Camera) and then trying to call the function when boosting is true
if (follow_this.boost):
currentFOV = boostFOV
camExtScript.shake(0.2,15,8)
else:
currentFOV = maxFOV
I’m also changing the FOV when the car is boosting. But can’t get the cam to shake.
Cheers
eyeEmotion | 2020-04-12 16:59
Don’t mind if I do. Zoink.
Zedespook | 2020-04-12 17:46
Thanks! Any need to initialize _previous_x/y
to rand_range(-1.0, 1.0)
(randf_range(-1.0, 1.0)
in Godot 4) rather than 0? It seems to only affect the slope at the very beginning but since we start from 0, isn’t it technically more correct to set them to 0? I couldn’t observe any difference.
Hyper Sonic | 2023-05-16 16:25