First Person Camera Movement Sway and Idle Sway

By creating a local script in StarterPlayerScripts, you can now have camera sway when you move your mouse, you will also have camera sway when you are not moving to apply a breathing effect.

Create a local script and paste it in StarterPlayerScripts. Hopefully this helps developers out.

--Services
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")

--constants
local PLAYER = Players.LocalPlayer
local CAMERA = workspace.CurrentCamera
local SX,SY = .05,.04 -- IDLE sway speed
local MXY = 0.0005 --center position
local SIN,PI_2 = math.sin,math.pi*2
local IDLE_LERP_SPEED = .01

--varibables 
local ix,iy = 0,0
local lsx,lsy = SX,SY
local lx,ly = MXY,MXY

--variables
local turn = 0

local lerp = function(a, b, t) return a + (b - a) * t end

PLAYER.CameraMode = Enum.CameraMode.LockFirstPerson

RunService:BindToRenderStep("CameraSway", Enum.RenderPriority.Camera.Value + 1, function(deltaTime)
	local MouseDelta = UserInputService:GetMouseDelta()
	turn = lerp(turn, math.clamp(MouseDelta.X, -3, 3), (15 * deltaTime))
	
	lsx=lerp(lsx,SX,IDLE_LERP_SPEED)
	lx=lerp(lx,MXY,IDLE_LERP_SPEED)
	lsy=lerp(lsy,SY,IDLE_LERP_SPEED)
	ly=lerp(ly,MXY,IDLE_LERP_SPEED)
	
	ix = (ix + lsx)%PI_2
	iy = (iy + lsy)%PI_2

	CAMERA.CFrame = CAMERA.CFrame * CFrame.Angles(0, 0, math.rad(turn)) * 
        CFrame.Angles(SIN(ix)*lx,SIN(iy)*ly,0)
end)
30 Likes

Updated Version, which also pauses a second before idle sway so the two sways are not interfering which each other.

--Services
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local Players = game:GetService("Players")

--constants
local PLAYER = Players.LocalPlayer
local CAMERA = workspace.CurrentCamera
local SX,SY = .05,.04 -- IDLE sway speed
local MXY = 0.0005 --center position
local SIN,PI_2 = math.sin,math.pi*2
local IDLE_LERP_SPEED = .01

--varibables 
local ix,iy = 0,0
local lsx,lsy = SX,SY
local lx,ly = MXY,MXY

--variables
local turn = 0
local lastCFramePosition = nil
local lastMoveTick = tick()

local lerp = function(a, b, t) return a + (b - a) * t end

PLAYER.CameraMode = Enum.CameraMode.LockFirstPerson

RunService:BindToRenderStep("CameraSway", Enum.RenderPriority.Camera.Value + 1, function(deltaTime)
	local MouseDelta = UserInputService:GetMouseDelta()
	turn = lerp(turn, math.clamp(MouseDelta.X, -3, 3), (15 * deltaTime))
	
	lsx=lerp(lsx,SX,IDLE_LERP_SPEED)
	lx=lerp(lx,MXY,IDLE_LERP_SPEED)
	lsy=lerp(lsy,SY,IDLE_LERP_SPEED)
	ly=lerp(ly,MXY,IDLE_LERP_SPEED)
	
	ix = (ix + lsx)%PI_2
	iy = (iy + lsy)%PI_2
	
	CAMERA.CFrame = CAMERA.CFrame * CFrame.Angles(0, 0, math.rad(turn))
	
	if lastCFramePosition and (lastCFramePosition - CAMERA.CFrame.Position).magnitude > .01 then lastMoveTick = tick() end
	
	if tick() - lastMoveTick > 1 then CAMERA.CFrame = CAMERA.CFrame * CFrame.Angles(SIN(ix)*lx,SIN(iy)*ly,0) end
	
	lastCFramePosition = CAMERA.CFrame.Position
end)

16 Likes

Its really nice ngl, love it the camera swaying! - will be a good edition to horror games!

4 Likes

could you add some videos or gifs of the effect in action? It’d help to know in advance what it looks like and what it does

Otherwise, a neat effect

1 Like

Here is the code in action!
https://gyazo.com/ca119805aedeccd522396c94e781e18d

This is a great resource, thank you!

If you wouldn’t mind, however; could you provide a small explanation of each part of the code as it may be confusing for some to understand!