Screen Shaking To Audio: A Little Too Shaky

(Before I start, please…I beg of you…ignore the outfit. I lost to a bet and am forced to wear this.


I’ve been working on a script that increases the Field Of View, corresponding to the music’s loudness. (In other words, FOV increasing to the beat).

Here’s the code that I have:

local RunService = game:GetService("RunService")

local Music = workspace:WaitForChild("Sound")
local CurrentCamera = workspace.CurrentCamera

local ScreenShakeSettings = {
	CameraMinFOV = 75,
	CameraMaxFOV = 80,
	CameraMaxVolume = 1200
}


game:GetService("RunService").RenderStepped:connect(function()
	local CurrentLoudness = Music.PlaybackLoudness
	local FOV = ScreenShakeSettings.CameraMinFOV + (ScreenShakeSettings.CameraMaxFOV - ScreenShakeSettings.CameraMinFOV) * (CurrentLoudness / ScreenShakeSettings.CameraMaxVolume)
	if FOV >= 75 then
		CurrentCamera.FieldOfView = FOV
	else
		CurrentCamera.FieldOfView = 75
	end
end)

Now, this script works just fine (that’s why it’s in Code Review). However, I’m not satisfied with how shaky it is.

Example:

It may be hard to tell because of the lighting. But if you look, the screen is constantly shaking, instead of shaking to the music’s beat. It creates a very irritating effect and isn’t what I’m going for.

Games like Vibe Bus are a perfect example of how I want it to look:

If anyone could help me improve my code to work smoother like Vibe Bus, it would be very much so appreciated. Thank you!

7 Likes

Have you tried rounding the loudness at all? For example rounding to the nearest 10, or nearest 100. That way small changes result in a constant fov.

You will, however, need some easing between FOVs depending on what number you choose to round to, otherwise it might result in fairly sudden changes.

4 Likes

What exactly do you mean when you say “loudness?”

Do you mean the loudness in the properties of the sound or the “CameraMaxVolume” in the script (or other, of course)?

Also, thanks for your response!

1 Like

You could try subtracting 10 or 20 from the FOV variable, that way the screen will only shake if the PlaybackLoudness is greater than 10 or 20. This would be similar to BanTech’s idea.

Also, not sure if you’re aware but the default FOV is 70 (not sure if you did 75 on purpose though)

2 Likes

Why don’t you just add a wait to the FOV change? I had this issue, I just would add a wait(.1) after you change the FOV of the camera.

1 Like

Either could work. Below are functionally equivalent, as they all force 10 FOV increments.

local CurrentLoudness = Music.PlaybackLoudness

-- Round to the nearest 120:
local RoundedLoudness = 120 * math.round(CurrentLoudness / 120)

-- Use the rounded loudness
local FOV = ScreenShakeSettings.CameraMinFOV + (ScreenShakeSettings.CameraMaxFOV - ScreenShakeSettings.CameraMinFOV) * (RoundedLoudness / ScreenShakeSettings.CameraMaxVolume)
	
local CurrentLoudness = Music.PlaybackLoudness
local FOVRaw = ScreenShakeSettings.CameraMinFOV + (ScreenShakeSettings.CameraMaxFOV - ScreenShakeSettings.CameraMinFOV) * (RoundedLoudness / ScreenShakeSettings.CameraMaxVolume)

-- Round to the nearest 0.5:
local FOV = 0.5 * math.round(FOVRaw / 0.5)
local CurrentLoudness = Music.PlaybackLoudness
local LoudnessFactor = CurrentLoudness / ScreenShakeSettings.CameraMaxVolume

-- Round to the nearest 0.1:
local RoundedFactor = 0.1 * math.round(LoudnessFactor / 0.1)

-- Use the rounded factor
local FOV = ScreenShakeSettings.CameraMinFOV + (ScreenShakeSettings.CameraMaxFOV - ScreenShakeSettings.CameraMinFOV) * RoundedFactor

I personally would recommend the third option, as the number of increments in the first two is determined by the max loudness or the FOV range, whereas the third option is obvious at a glance that the factor will go up in 0.1 and therefore has 10 increments.

Again, not sure how violent this will be, probably needs a combo of fine tuning the number of increments and if it’s still too sudden, possibly an easing function to actually set the FOV. See how you get on first

1 Like

Hey! I’m gonna share with you the way I did it in my vibe game, since you’re setting the FOV obviously it’s gonna look bad, what I did and what I would recommend is using a tween, tweening the camera.FieldOfView!

Here’s an example of how mines looks:

https://gyazo.com/3bbe462590a00372fd32880d65d043a5

function soundPlayback()
	local Camera = workspace.CurrentCamera -- reference this somewhere at the top to cache
	local Tween = game:GetService("TweenService") -- same with this
	local Info = TweenInfo.new(0.10, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut) -- also this.

	local Properties

	if (sound.PlaybackLoudness/1000) >= 0.30 and Camera.FieldOfView < 74 then
		Properties = {FieldOfView = 68 + (sound.PlaybackLoudness/100)}
	else
		Properties = {FieldOfView = 68 - (sound.PlaybackLoudness/1000)}
	end

	local T = Tween:Create(Camera, Info, Properties)
	T:Play()
end

The code above is what I did in order to tween it using renderstepped - this is all client.
Code is messy but gives you an idea of what looks nice I’d guess.

3 Likes

You’re incredible. Thank you so much!

So if it’s all client, then would it go in ServerScriptService or somewhere else?

1 Like

You can put this in, “StarterPlayerScripts”. If you have any other questions let me know!

1 Like

That looks very cool! How did you make the blur effect on beat?

Sorry never saw this show up in my notifications, I never really used a blur effect. Could have been maybe the lighting, to be honest. - I had changed some of the lighting to suit the theme.

1 Like

Personally, I used the bloom effect + that script to accent neon objects like you’re asking.

1 Like

I know that you have already solved this, but there is something I wanted to add in case you stumbled upon the following obstacle, and that is sound.PlaybackLoudness not being representative of the actual beats. If a song is very simple and clean, then this is not a problem since the beats will probably represent the peaks in terms of volume. However, in many songs the audio can get loud without any beats playing because of secondary accompanying effects, and using the above solution will desynchronize from rhythm making the animation look messy.
What you could do instead, if you don’t use a huge library of songs, is look for the BPMs and drop intervals for each of the songs you are playing, as they can be easily found online for most, or you could just browse for a BPM detector.

I have used the method described in my game and this is the result, although quite messy because of the number of players (the video is big so feel free to skip anywhere to observe the effect):

PS

Ignore the video’s title, it was meant only for the members of our small community :stuck_out_tongue: .

3 Likes

Would you be so kind enough to share the code or help me make something like that (“Screen capture - 3bbe462590a00372fd32880d65d043a5 - Gyazo”)? I personally never used bloom and would love to see how to make something like that. Anything is appreciated!

Very profound post! And great game! I wish you the best of luck.

Although using BPM would prove efficient, I feel that using such a method would take away from the feel I want to give players of the screen animating to the song’s beat if it were such a constant movement.

However, for games with such an upbeat them as yours, I feel that the BPM method works perfectly, for too much movement would cause confusion in the gameplay. But for Vibe games, I feel that extra movement is needed.

Thanks for your post! I’ll definitely look back to this in the future if I create such an upbeat game.

2 Likes

this looks great, but isn’t it kind of inefficient?

It really depends on what audio you’re using. Since a general use of this is for Lofi songs, the songs usually have more “bass-boosted” beats, allowing the FOV shake to work.

With more intense songs where the song’s general elements are all the same volume, it can prove inefficient. However, as I said before, the general use for this is for LQ-boosted songs, so it works just fine.

1 Like

Hello, can you help me, I don’t know where I’m supposed to put the song.

An alternative is using exponential math to have it “cap” more and more as the volume increases.

To the OP, you can use the ^ symbol, with a number less than 1 to exponentially round it off.