Problem:
I used this view bobbing script that moves the screen when the player walks or sprints. The view bobbing works perfectly fine when on 60 FPS but when the player's FPS is low or high (Using an FPS unlocker), then the view bobbing either becomes slow/fast depending on the FPS.
60 FPS (The view bobbing I’m aiming for):
360 and 30 FPS (On 360 FPS the screen moves too fast, probably because of how fast the FPS is. On 30 FPS the screen moves too slow, probably because of how slow the FPS is):
Script:
--!strict
-- SERVICES --
local RunS = game:GetService("RunService")
local TweenS = game:GetService("TweenService")
-- VARIABLES --
local Player = game.Players.LocalPlayer
local Char = Player.Character or Player.CharacterAdded:Wait()
local Hum = Char:WaitForChild("Humanoid")
local RootPart = Char:WaitForChild("HumanoidRootPart")
local Camera = workspace.CurrentCamera
--
local TiltIntensity_Folder = script:WaitForChild("TiltIntensity")
local TiltSpeed_Folder = script:WaitForChild("TiltSpeed")
local BobbingIntensity_Folder = script:WaitForChild("BobbingIntensity")
local BobbingSpeed_Folder = script:WaitForChild("BobbingSpeed")
--
local bobbing = nil
local tiltSideSpeed : number = TiltSpeed_Folder.SideSpeed.Value -- Default: 0.05
local tiltSpeed : number = TiltSpeed_Folder.Speed.Value -- Default: 0.08
local tiltIntensity : number = TiltIntensity_Folder.Walking.Value -- Default: 1.5
local bobbingSpeed : number = BobbingSpeed_Folder.Speed.Value -- Default: 0.155
local bobbingIntensityWalking : number = BobbingIntensity_Folder.Walking.Value -- Default: 0.008
local bobbingIntensitySprinting : number = BobbingIntensity_Folder.Sprinting.Value -- Default: 0.02
--
local tilt : number = 0
local tiltValue : number = 0
local sinValue : number = 0
-- FUNCTIONS --
function lerp(a : number, b : number, t : number) : number
return a + (b - a) * t
end
function calculateSine(speed : number, intensity : number) : CFrame
sinValue += speed
if sinValue > (math.pi * 2) then sinValue = 0 end
local sineY : number = intensity * math.sin(2 * sinValue)
local sineX : number = intensity * math.sin(sinValue)
local sineCFrame : CFrame = CFrame.new(sineX, sineY, 0)
return sineCFrame
end
function calculateTilt(speed : number, intensity : number) : CFrame
tiltValue += speed
if tiltValue > (math.pi * 2) then
tiltValue = 0
end
local sineY : number = intensity * math.sin(2 * tiltValue)
local sineX : number = intensity * math.sin(tiltValue)
local sineCFrame : CFrame = CFrame.new(sineX, sineY, 0)
return sineCFrame
end
local previousSineX : number = 0
local previousSineY : number = 0
local previousTilt : number = 0
-- Camera sway loop
bobbing = RunS.RenderStepped:Connect(function(dt : number)
-- Check if the humanoid is dead
if Hum.Health <= 0 then
bobbing:Disconnect() -- Disconnect view bobbing when dead
return
end
local movementVector : Vector3 = Camera.CFrame:VectorToObjectSpace(RootPart.AssemblyLinearVelocity / math.max(Hum.WalkSpeed, 0.01) * tiltIntensity)
local speedModifier : number = (Hum.WalkSpeed / 16)
tilt = math.clamp(lerp(tilt, movementVector.X * tiltSideSpeed, 0.1), -0.25, 0.1)
local sineCFrame : CFrame = calculateSine(bobbingSpeed * speedModifier, movementVector.Magnitude * 1)
local tiltCFrame : CFrame = calculateTilt(tiltSpeed * 1, movementVector.Magnitude * 1)
local lerpedSineX : number
local lerpedSineY : number
if speedModifier <= 1 then
lerpedSineX = lerp(previousSineX, sineCFrame.X, bobbingIntensityWalking * speedModifier)
lerpedSineY = lerp(previousSineY, sineCFrame.Y, bobbingIntensityWalking - 0.001 * speedModifier) -- Don't move much on Y-axis
tiltIntensity = TiltIntensity_Folder.Walking.Value
else
lerpedSineX = lerp(previousSineX, sineCFrame.X, bobbingIntensitySprinting * (speedModifier * 1.2))
lerpedSineY = lerp(previousSineY, sineCFrame.Y, bobbingIntensitySprinting - 0.001 * (speedModifier * 1.2)) -- Don't move much on Y-axis
tiltIntensity = TiltIntensity_Folder.Sprinting.Value
end
local lerpedTilt : number = lerp(previousTilt, tiltCFrame.Y, 0.001)
TweenS:Create(Camera, TweenInfo.new(dt, Enum.EasingStyle.Quad), {CFrame = Camera.CFrame * CFrame.Angles(0, 0, -tilt + lerpedTilt) * CFrame.new(lerpedSineX, lerpedSineY, 0)}):Play()
previousSineX = lerpedSineX
previousSineY = lerpedSineY
previousTilt = lerpedTilt
end)
Failed Solutions:
1.) Changed RenderStepped to Heartbeat, Stepped, etc. It just breaks the camera.
2.) Experimented with "dt" (DeltaTime). Didn't work out for me because I'm not that good at math. I think the solution has something to do with that variable but I just don't know how to use it.
Any kind of help will be very useful since I’m stuck at this, I’m not the best at math.