How do I make a gentle camera shake?

Hi,

I want to make a gentle camera shake, and I want it to work like the shake in this video:

I want it to work when the player is seated only in a specific seat (in this case, the aircraft seat), and I want the magnitude of the shake to increase as the throttle (engine power) increases (I’ll just learn how to get a button to pop up, and when pressed, shakes the screen gently for 10 seconds).

How would I achieve this?

7 Likes

you can use the tween service on the camera in a local script, you can read about it here:TweenService | Documentation - Roblox Creator Hub, here is an example of what you could do:

--local script
local tweenService = game:GetService("TweenService")
local camera = workspace.CurrentCamera
local tweenInfo = TweenInfo.new(1,Enum.EasingStyle.Quad,Enum.EasingDirection.Out)
local cameraTweenGoal = {
      [CFrame] = camera.CFrame * CFrame.new(-5,0,0)
}
local cameraTween = tweenService:create(camera,tweenInfo,cameraTweenGoal)
camera.CameraType = Enum.CameraType.Scriptable
cameraTween:Play()
--this is a simple illustration of how to use the tween service on the camera
3 Likes

Have you ever seen graphs of sin x or cos x? They generate smooth ‘waves’ which we can use to our advantage. We will also need a timer, you can use time() or tick() but I wouldn’t recommand it because if you want to suddenly increase the shake it’s more difficult with that. We can’t use runService.Heartbeat to apply camera effects to the player. It’ll look a bit wierd and off. That’s why we’re going to use runService:BindToRenderStep(). BindToRenderStep does exactly what it says. It runs the function you put each time the screen gets refreshed. I won’t go exactly in detail in how it works but if you’re interrested you can click here.
Now let’s start coding a bit. First we need to bind the function with the renderloop.

local rService = game:GetService("RunService")
local ShakeTimer = 0

function render_loop() --this function will run each time the screen gets refreshed
	ShakeTimer = ShakeTimer + .03 --increase the timer ~30 frames/sec
end

--run this when you want the effect to be enabled
workspace.CurrentCamera.CameraType = Enum.CameraType.Scriptable
rService:BindToRenderStep("renderloop",200,render_loop)
--run this when you want the effect to be gone
workspace.CurrentCamera.CameraType = [[whatever it was before you changed it]]
rService:UnbindFromRenderStep("renderloop")

Remember what you had CameraType set to before so you can reset it to that after the effect is finished.
Now we haven’t done anything yet with the camera. We’ll do that now. You will want to multiple the camera angle by CFrame.Angles(math.cos(timer),math.sin(timer),0). There’s only 1 problem with this. This is not gentle shake, you will want to reduce the effect cos and sin create. Just multiply them by a really low number. I used a multiplier of 0.00825 and it works nicely for me. Now when you did all of this you got a nice shake. But the form the shake takes effect in isn’t that nice. It just makes the screen go around in circles. If that’s what you want this is perfect. But I wouldn’t like that very much. I want to create a shake in the form of: image
luckily, that is just possible! We’ll need to modify sin and cos a bit more tho. We currently have: CFrame.Angles(math.cos(timer)*.00825,math.sin(timer)*.00825,0). To get the shape that we want we will need to increase the value of timer inside of sin and cos. To get the shape I showed you’ll need to change the it this: CFrame.Angles(math.cos(timer*2)*.00825,math.sin(timer+math.pi/4)*.00825,0)
Now if we return to the function. We now have this:

local rService = game:GetService("RunService")
local ShakeTimer = 0

local range = 0.00825 --I wrote these down here so you can easily modify them
local speed = 0.03

function render_loop() --this function will run each time the screen gets refreshed
	ShakeTimer = ShakeTimer + speed --increase the timer ~30 frames/sec
	workspace.CurrentCamera.CFrame = workspace.CurrentCamera.CFrame * CFrame.Angles(math.cos(timer*2)*range,math.sin(timer+math.pi/4)*range,0)
end

--run this when you want the effect to be enabled
workspace.CurrentCamera.CameraType = Enum.CameraType.Scriptable
rService:BindToRenderStep("renderloop",200,render_loop)
--run this when you want the effect to be gone
workspace.CurrentCamera.CameraType = [[whatever it was before you changed it]]
rService:UnbindFromRenderStep("renderloop")

And that should be it really, if you want to modify the shake just change speed and range until you find the perfect fit!

36 Likes

This is a super detailed response, I’ll be sure to try it later today! Thanks for replying!

1 Like

I’ll try and give this a go too, thanks!

1 Like

I used CameraOffset on humanoid for the shaking

1 Like