How do you recreate this camera wobble effect?

I’ve seen this one camera wobble based on rotation in so many Roblox games but I can’t find any posts on it at all. I’ve tried many times to do it myself but I just can’t find out how they did it.

Heres what I’m trying to recreate (SCP: anomaly breach 2):

As you can see, there is a slight rotation wobble on the z-axis if I’m correct.
Thanks!

19 Likes

You can manipulate a cameras CFrame to rotate it or move it.

local Player = game:GetService("Players").LocalPlayer
local Char = game.Workspace:WaitForChild(Player.Name)
local Hum = Char:WaitForChild("Humanoid")
local RS = game:GetService("RunService")
RS.RenderStepped:Connect(function()
	local CT = tick()
	if Hum.MoveDirection.Magnitude > 0 then
		local BobbleX = math.cos(CT*10)*0.25
		local BobbleY = math.abs(math.sin(CT*10))*0.25
		local Bobble = Vector3.new(BobbleX,BobbleY,0)
			Hum.CameraOffset = Hum.CameraOffset:lerp(Bobble, 0.25)
	else
		Hum.CameraOffset = Hum.CameraOffset * 0.75
	end
end)

This script is used to bobble the x axis and the y axis, the only way you can do z axis is if you use CFrame

Credits to Okeanskiy

10 Likes

I’ve tried that before but then you need to make the camera type scriptable and then the player has no control over the camera anymore. :confused:

It isn’t changing the camera, just CameraOffset.

1 Like

Make the cameras position at the players head, then set the camera to look at the players mouse. Still complete control over the camera this way. (You may want to make the head invisible on the client)

local Camera = Player.CurrentCamera
local Mouse = Player:GetMouse()
local Character = Player.CharacterAdded(Character)
Camera.CameraType = "Scriptable"

while true do
    Camera.CFrame = Cframe.new(Character.Head.Position,Mouse.Hit)
    wait(0.05)
end

-- then when the char is walking make the camera shake a bit
1 Like

I’ve also tried this before and it never stops rotating the camera:

You have to make the mouse blacklist the character, what’s happening is the mouse is hitting the character and trying to look at it. If you blacklist then the mouse will ignore the character.

I would also add some looking limits later on so the character cant look down or up past a certain point (There’s a reason for this.)

Your other option is to attach the camera to the face of the character and move the head. This way you can actually animate it to make the camera move too e.g for the walking

1 Like

I tried this and the same thing happened, I know there’s a way to control the camera with the mouse delta, but I haven’t found a way to do that either.

This only wobbles the position, I need to wobble the rotation.

try this:
local runService = game:GetService(“RunService”)

local plr = game.Players.LocalPlayer

local chr = plr.Character

local humrootpart = chr:WaitForChild(“HumanoidRootPart”)

local hum = chr:WaitForChild(“Humanoid”)

local cam = workspace.Camera

local tiltSpeedZ = 0.1

local bobbingSpeed = 0.1

local tilt = 0

local sinValue = 0

function lerp(a, b, t)

return a + (b - a) * t

end

function calculateSine(speed, intensity)

sinValue += speed

if sinValue > (math.pi * 2) then sinValue = 0 end

local sineY = intensity * math.sin(2 * sinValue)

local sineX = intensity * math.sin(sinValue)

local sineCFrame = CFrame.new(sineX, sineY, 0)

return sineCFrame

end

local previousSineX = 0

local previousSineY = 0

runService.RenderStepped:Connect(function(dt)

local movementVector = cam.CFrame:vectorToObjectSpace(humrootpart.Velocity / math.max(hum.WalkSpeed, 0.01))

local speedModifier = (hum.WalkSpeed / 16)

tilt = math.clamp(lerp(tilt, movementVector.X * tiltSpeedZ, 0.1), -0.25, 0.1)

local sineCFrame = calculateSine(bobbingSpeed * speedModifier, movementVector.Z * speedModifier)

local lerpedSineX = lerp(previousSineX, sineCFrame.X, 0.1)

local lerpedSineY = lerp(previousSineY, sineCFrame.Y, 0.1)

cam.CFrame *= CFrame.Angles(0, 0, tilt) * CFrame.new(lerpedSineX, lerpedSineY, 0)

previousSineX = lerpedSineX

previousSineY = lerpedSineY

end)

4 Likes

Now Updated! Camera Bobble V2 - Roblox

if its supposed to be a localscript. while true do isnt perfect

Camera is a local instance, unless you have parts acting as players cameras in the server side with the local setting the camera to that position. Also loops work fine both locally and on server, if your on about syncing then that just has to be done the right way.

It’s not exactly about syncing, as it’s more about having less choppy input+camera rotation using (usually) RenderStepped which fires before the frame is rendered, whereas while true do might run before or after the frame, as it really isn’t synced to the screen/framerate at all.

2 Likes

This makes the player’s body rotate when in first person

4 Likes

sorry for bumping but i managed to find a script and modified a bit, heres the script

repeat wait() until game.Players.LocalPlayer.Character

-- Varibles you can change
local RotationAmount =  30  -- the smaller, the bigger the amount.
local Rotation =        1.5 -- i have no idea what it does, play around it till it looks good
local PositionAmount = -3   --keep minus, the smaller, the bigger the amount.
local Position =        3   -- i have no idea what it does, play around it till it looks good
-----------------------------
camera = game.Workspace.CurrentCamera
character = game.Players.LocalPlayer.Character

Z = 0

damping = character.Humanoid.WalkSpeed / 3 -- dont set it under 3

PI = 3.1415926

local tick = PI / 2

running = false
strafing = false

character.Humanoid.Strafing:connect(function(bool)
	strafing = bool
end)

character.Humanoid.Jumping:connect(function()
	running = false
end)

character.Humanoid.Swimming:connect(function()
	running = false
end)

character.Humanoid.Running:connect(function(speed)
	if speed > 0.1 then
		running = true
	else
		running = false
	end
end)

function mix(par1, par2, factor)
	return par2 + (par1 - par2) * factor
end

while true do
	game:GetService("RunService").RenderStepped:wait()
	
	fps = (camera.CoordinateFrame.p - character.Head.Position).Magnitude
	
	if fps < 0.52 then
		Z = 1
	else
		Z = 0
	end
	
	if running == true and strafing == false then
		tick = tick + character.Humanoid.WalkSpeed / 92 --Calculate Bobbing speed.
	else
		if tick > 0 and tick < PI / 16 then
			tick = mix(tick, PI / 16, 14.9)
		end
		if tick > PI / 2 and tick < PI then
			tick = mix(tick, PI / 16, 14.9)
		end
		if tick > PI and tick < PI * 15.5 then
			tick = mix(tick, PI * 15.5, 14.9)
		end
		if tick > PI * 1.5 and tick < PI * 15 then
			tick = mix(tick, PI * 15.5, 14.9)
		end
	end
	
	if tick >= PI * 15 then
		tick = 0
	end	
	
	camera.CoordinateFrame = camera.CoordinateFrame * 
		CFrame.Angles(0, 0, math.sin(tick - PI * Rotation) / (damping * RotationAmount)) + Vector3.new(0,math.sin(tick - PI * Position) / (damping * PositionAmount),0) --Set camera CFrame
end
3 Likes

I know I’m late, but y’know,

This was made using @NoTaxEvading and @minimic2002 's answers.

local Player = game:GetService("Players").LocalPlayer
local Mouse = Player:GetMouse()

local Char = game.Workspace:WaitForChild(Player.Name)
local Hum = Char:WaitForChild("Humanoid")

local RS = game:GetService("RunService")

local Camera = workspace.CurrentCamera

repeat wait()
	workspace.CurrentCamera.CameraType = Enum.CameraType.Scriptable
until workspace.CurrentCamera.CameraType == Enum.CameraType.Scriptable

RS.RenderStepped:Connect(function()
	local CT = tick()
	
	Camera.CFrame = (Mouse.Hit.Parent == Char or Mouse.Hit.Parent.Parent == Char) and CFrame.new(Char.Head.Position, Mouse.Hit)
	if Hum.MoveDirection.Magnitude > 0 then
		local BobbleX = math.cos(CT*10)*0.25
		local BobbleY = math.abs(math.sin(CT*10))*0.25
		local Bobble = Vector3.new(BobbleX,BobbleY,0)
		Hum.CameraOffset = Hum.CameraOffset:lerp(Bobble, 0.25)
	else
		Hum.CameraOffset = Hum.CameraOffset * 0.75
	end
end)
2 Likes

Seeing as most solutions here are either broken or unnecessarily long, here’s my take on the bob effect.

local RNS = game:GetService("RunService")

local camera = workspace.CurrentCamera	
local char = script.Parent
local HRP: BasePart = char:WaitForChild("HumanoidRootPart")
local rotFrequency, rotIntensity = 4.6, 1.35 -- camera rotation on z axis (frequency is how fast, intensity is how strong)
local verFrequency, verIntensity = 8.35, .25 -- camera movement on y axis (frequency is how fast, intensity is how strong)
local defWalkSpeed = 20.3 -- default walk speed (so that whenever the walk speed increases, the walk bob gets faster)

local previousVelocity = nil

local function Lerp(a, b, t)
	return (a + (b - a) * t :: number)
end

local function GetCurve(frequency, intensity)
	return (math.sin(os.clock() * frequency) * intensity :: number)
end

RNS.RenderStepped:Connect(function()
	local velocity = math.round(Vector3.new(HRP.AssemblyLinearVelocity.X, 0, HRP.AssemblyLinearVelocity.Z).Magnitude)
	if previousVelocity then
		velocity = Lerp(previousVelocity, velocity, .25)
	end
	previousVelocity = velocity
	
	camera.CFrame *= CFrame.new(0, GetCurve(verFrequency, verIntensity) * velocity / defWalkSpeed, 0) * CFrame.Angles(0, 0, math.rad(GetCurve(rotFrequency, rotIntensity) * velocity / defWalkSpeed))
end)

34 Likes