Above is a great video on camera manipulation, and also goes into a method I like on acheiving camera shake.
The only case I can think where you want to “override” the camera is for cutscenes and similar things where you want to control the camera in a specific way. For camera shake, you can “add on” the shake onto the already existing camera CFrame (which is creating the 2D perspective).
The basic idea is that the camera has “trauma”, which decreases linearly over time, and camera shake is trauma sqaured or cubed, so exponential. It also uses perlin noise, so that the shake is “smoother”- overall a nicer experience for the player.
Each frame, you want to calculate the trauma. Here is the function, which comes from the video, but into Luau and for Roblox:
local function calculateTrauma(dt)
local seed = math.random(0, 500)
local transform = {
(MAX_ANGLE * math.noise(seed, dt * FREQUENCY) * 2 - 1) * math.pow(trauma, 2),
(MAX_ANGLE * math.noise(seed + 1, dt * FREQUENCY) * 2 - 1) * math.pow(trauma, 2),
(MAX_ANGLE * math.noise(seed + 2, dt * FREQUENCY) * 2 - 1) * math.pow(trauma, 2),
}
trauma = math.clamp(trauma - RECOVERY_SPEED * dt, 0, 1)
local angle = CFrame.fromEulerAnglesXYZ(math.rad(transform[1]), math.rad(transform[2]), math.rad(transform[3]))
camera.CFrame *= angle
end
FREQUENCY
, RECOVERY_SPEED
, and MAX_ANGLE
are just some values, and it’s explained in the video. You can play around with these values, but I think these work well to start off with:
local FREQUENCY = 75
local RECOVERY_SPEED = 1.5
local MAX_ANGLE = 2
trauma
keeps track of the current trauma, and when it’s initialised it’s set to 0.
local trauma = 0
And then run this function every frame, passing in delta time as the argument.
RunService.RenderStepped:Connect(function(dt) -- will be deprecated soon!
calculateTrauma(dt)
end)
Whenever you want to “induce stress” on the camera i.e. make the camera shake, you can have some function to add trauma which will clamp the amount of stress you can add to 1, so it’s not an unbearable amount of shaking, like so:
local function addTrauma(stress)
trauma = math.clamp(trauma + stress, 0, 1)
end
Hope this helps. Take a look at the video and it should explain more in detail.