Custom camera tweening being delayed if fps is high [SOLVED]

Hello! So for the past few months I’ve been developing a game, and one part of it was a custom camera system. If you use regular Roblox’s capped 60 fps, it works fine. However, since there’s a high chance that Roblox will eventually add a higher FPS support, I decided to download an FPS unlocker. However, when I played my game with the FPS unlocker, this happened:

For reference, this is what it’s supposed to look like:

I assume it’s caused by how the tweening system of the camera works, and I tried solving it with math, but it really never ended up working. Here’s the camera code:

task.wait()
local camera = workspace.CurrentCamera

camera.CameraType = Enum.CameraType.Scriptable

local plr = game.Players.LocalPlayer
local char = plr.Character
local mouse = plr:GetMouse()

local screenshake = false
local screenshakepower = 0

local campart = game.Workspace:WaitForChild("CamPart")
local maxTilt = 5
local ts = game:GetService("TweenService")
local angle = "front"

local previousposition = Vector3.new(0,0,0)

local cando = true

local ismonster1 = false
	
game:GetService("RunService").Heartbeat:Connect(function()
	local offset = Vector3.new(0,0,0)
	local humroot = char:FindFirstChild("HumanoidRootPart")
	if cando == true then
		local asd = 0
		camera.FieldOfView = 72.5
		if angle == "right" then
			offset = Vector3.new(0,1.5,10)
		end
		if angle == "left" then
			offset = Vector3.new(0,1.5,-10)
		end
		if angle == "front" then
			offset = Vector3.new(-10,1.5,0)
		end
		if angle == "top" then
			offset = Vector3.new(-2,15,0)
		end
		if angle == "back" then
			offset = Vector3.new(10,1.5,0)
		end
		if angle == "angledfront" then
			offset = Vector3.new(-10,7,0)
		end
		if angle == "birds" then
			offset = Vector3.new(-2,25,0)
		end
		local crouchscript = game.Players.LocalPlayer.Character:FindFirstChild("CrouchScript")
		if crouchscript ~= nil then
			if crouchscript.Crouch.Value == true then
				offset = offset - Vector3.new(0,2,0)
			end
		end
	end
	
	local valuee = 0.07
	
	if screenshake == true then
		print("changed")
		offset = offset + Vector3.new(math.random(screenshakepower * -1, screenshakepower),math.random(screenshakepower * -1, screenshakepower),math.random(screenshakepower * -1, screenshakepower))
	end
	if cando == true then
		if humroot ~= nil then
			if ismonster1 == false then
				local twen = ts:Create(campart, TweenInfo.new(valuee,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut), {CFrame = CFrame.new((humroot.Position + offset), humroot.Position)})
				camera.FieldOfView = 70
				twen:Play()
			else
				local twen = ts:Create(campart, TweenInfo.new(valuee,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut), {CFrame = CFrame.new((humroot.Position + (offset + Vector3.new(0,1.5,0))), game.Workspace.CameraLookAt.Position)})
				camera.FieldOfView = 105
				twen:Play()
			end
		end
	else
		if screenshake == true then
			local twen = ts:Create(campart, TweenInfo.new(valuee,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut), {Position = previousposition + offset})
			twen:Play()
		end
	end
	camera.CFrame = campart.CFrame * CFrame.Angles(
		math.rad((((mouse.Y - mouse.ViewSizeY / 1.5)/mouse.ViewSizeY)) * -maxTilt),
		math.rad((((mouse.X - mouse.ViewSizeX / 1.5)/mouse.ViewSizeX)) * -maxTilt),
		0
	)
end)

I have no idea where to start to fix this, so that’s why I’m at devfourm. Please help!

4 Likes

That’s because you’re using Heartbeat. Because the game is running at a higher fps, the heartbeat will be extremely low

1 Like

I tried other looping methods but all of them ended the same way. If it doesn’t update per frame it looks extremely choppy. Is it possible to detect the fps and change how the tween runs because of it?

1 Like

you can try using delta. Multiply the “valuee” with the delta time

1 Like

I tried to do what you said (local valuee = 0.07 x deltatime with setting deltatime in the heartbeat parentheses) and it just made it instantly go to the exact position of the player, without the smooth tween.

you can try to do it: valuee = (0.07 * deltatime) * 10

Same output. This is what you’re asking, right?

task.wait()
local camera = workspace.CurrentCamera

camera.CameraType = Enum.CameraType.Scriptable

local plr = game.Players.LocalPlayer
local char = plr.Character
local mouse = plr:GetMouse()

local screenshake = false
local screenshakepower = 0

local campart = game.Workspace:WaitForChild("CamPart")
local maxTilt = 5
local ts = game:GetService("TweenService")
local angle = "front"

local previousposition = Vector3.new(0,0,0)

local cando = true

local ismonster1 = false
	
game:GetService("RunService").RenderStepped:Connect(function(deltatime)
	local offset = Vector3.new(0,0,0)
	local humroot = char:FindFirstChild("HumanoidRootPart")
	if cando == true then
		local asd = 0
		camera.FieldOfView = 72.5
		if angle == "right" then
			offset = Vector3.new(0,1.5,10)
		end
		if angle == "left" then
			offset = Vector3.new(0,1.5,-10)
		end
		if angle == "front" then
			offset = Vector3.new(-10,1.5,0)
		end
		if angle == "top" then
			offset = Vector3.new(-2,15,0)
		end
		if angle == "back" then
			offset = Vector3.new(10,1.5,0)
		end
		if angle == "angledfront" then
			offset = Vector3.new(-10,7,0)
		end
		if angle == "birds" then
			offset = Vector3.new(-2,25,0)
		end
		local crouchscript = game.Players.LocalPlayer.Character:FindFirstChild("CrouchScript")
		if crouchscript ~= nil then
			if crouchscript.Crouch.Value == true then
				offset = offset - Vector3.new(0,2,0)
			end
		end
	end
	
	local valuee = (0.07 * deltatime) * 10
	
	if screenshake == true then
		print("changed")
		offset = offset + Vector3.new(math.random(screenshakepower * -1, screenshakepower),math.random(screenshakepower * -1, screenshakepower),math.random(screenshakepower * -1, screenshakepower))
	end
	if cando == true then
		if humroot ~= nil then
			if ismonster1 == false then
				local twen = ts:Create(campart, TweenInfo.new(valuee,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut), {CFrame = CFrame.new((humroot.Position + offset), humroot.Position)})
				camera.FieldOfView = 70
				twen:Play()
			else
				local twen = ts:Create(campart, TweenInfo.new(valuee,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut), {CFrame = CFrame.new((humroot.Position + (offset + Vector3.new(0,1.5,0))), game.Workspace.CameraLookAt.Position)})
				camera.FieldOfView = 105
				twen:Play()
			end
		end
	else
		if screenshake == true then
			local twen = ts:Create(campart, TweenInfo.new(valuee,Enum.EasingStyle.Sine,Enum.EasingDirection.InOut), {Position = previousposition + offset})
			twen:Play()
		end
	end
	camera.CFrame = campart.CFrame * CFrame.Angles(
		math.rad((((mouse.Y - mouse.ViewSizeY / 1.5)/mouse.ViewSizeY)) * -maxTilt),
		math.rad((((mouse.X - mouse.ViewSizeX / 1.5)/mouse.ViewSizeX)) * -maxTilt),
		0
	)
end)

Yea. That’s weird. Isn’t it working?

It basically just instantly teleports the camera to the players location, plus the offset.

Print Deltatime to see what it prints

Prints this: 0.01748039945960045.

try this: valuee = 0.07 * (deltatime * 60)

if you want to check the FPS of the game, you can do the equation 1/deltatime that would be equal to the fps

It works well at 60 fps, and starts to lag a little bit and bug at 240

try to do

valuee = 1 * deltatime

That’s weird… I don’t kow why it is like that.

it goes back to just following the player again :sob:

I was thinking that maybe the reason this (0.07 * (deltatime * 60)) was janky for the higher fps was maybe because of how the fps fluctuated. Is it possible to get average deltatime?

It worked flawlessly for the 60 fps one, probably because it stayed on the same fps

you can try doing a while true loop every .1 seconds or edit delay until you find it right. using render step or heartbeat for recoil or camera stuff like this specifically is going to result in high fps to have different desired result same for lower fps.