How do i make this sway script resist fps unlockers?

  1. What do you want to achieve? Keep it simple and clear!
    A camera sway script that does not speed up or slow down if fps changes

  2. What is the issue? Include screenshots / videos if possible!
    I did the sway part but now im stuck trying to make the sway be the same on any framerate

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    I know i have to use DeltaTime but i just dont know how to use it

I’ve been trying to find a solution for 4 hours now. Help

script:

if arms.PrimaryPart then
	runService.RenderStepped:Connect(function(DeltaTime) -- sway
		local Rotation = workspace.CurrentCamera.CFrame:ToObjectSpace(LastCameraCFrame)
		local X,Y,Z = Rotation:ToOrientation()
		SwayCFrame = SwayCFrame:Lerp(CFrame.Angles(math.sin(X) * SwayEffect, math.sin(Y) * SwayEffect, math.sin(Z) * SwayEffect), 0.1/DeltaTime/60)

		LastCameraCFrame = workspace.CurrentCamera.CFrame

		arms:SetPrimaryPartCFrame(cam.CFrame * SwayCFrame)
	end)
end

You can use tweenservice, learn more about it here. TweenService | Roblox Creator Documentation

fps doesn’t really affect speed when an animation plays. it just makes it smoother by adding more frames, hence its name.

OP is lerping, not using animations. FPS will affect the deltaTime returned by RunService events so if custom animations with CFrame are dependent on RunService then clients with a higher framerate may see unexpected results when triggering the animations (in this case, the swaying).

OP: Might want to play around with this 0.1/DeltaTime/60. Looks like you meant to write 60 * (1 > speed > 0) * DeltaTime maybe? I personally don’t know much about using deltaTime to influence speed but I do recall that use cases of it are multiplicative, not divisive.

3 Likes

What you want is to limit the rate, correct? Doing so is a relatively easy task if you understand the math and don’t overthink it.

The deltaTime argument that is passed to the connected function is the time that elapsed since that last RenderStep. Because this runs on the users hardware, the values this normally fluctuates between (ignoring lag) can be different for each device. However, you must keep in mind that this is not the total time passed.

What you need to do is create a variable to store the time passed and use this as measure for limiting the rate.

local TIMES_PER_FRAME = 1/20 --how often you want to update the camera every second (20 in this case)
local SWAY_SPEED = 1 --the speed you want the arms to sway at (you'll want to mess around with this)

local camera = workspace.CurrentCamera

local CurrentTime = 0 -- a local variable for storing the current elapsed time value
local LastCameraCFrame = camera.CFrame

-- other code...

if arms.PrimaryPart then
	runService.RenderStepped:Connect(function(DeltaTime) -- sway
		CurrentTime += DeltaTime
		
		if CurrentTime >= TIMES_PER_FRAME then
			local Rotation = camera.CFrame:ToObjectSpace(LastCameraCFrame)
			LastCameraCFrame = camera.CFrame
			
			local X,Y,Z = Rotation:ToOrientation()
			SwayCFrame = SwayCFrame:Lerp(CFrame.Angles(math.sin(X) * SwayEffect, math.sin(Y) * SwayEffect, math.sin(Z) * SwayEffect), SWAY_SPEED*CurrentTime) -- I probably have the math wrong here for the lerp value; I haven't done this in awhile
			
			arms:PivotTo(LastCameraCFrame * SwayCFrame) --replaced 'SetPrimaryPartCFrame' because it has been superseded by  'PivotTo'
			
			CurrentTime -= TIMES_PER_FRAME --you could also use the modulus operator here, but both would achieve different results in the event of noticeable lag over a duration
		end
	end)
end

EDIT:
Also, just a side note in case you didn’t know, when declaring variable constants (variables that don’t change like SWAY_SPEED) the standard naming convention is to use all uppercase, as this helps separate between your constants and normal variables and makes the code slightly more readable.

The arms are now moving like this
RobloxStudioBeta_iX1O5TYebK
I did change the rate to 60 after this though, but the same effect happens when i put it on 120 fps
So i changed the rate to 120 fps. I thought it was over, until the arms started moving around me like a circle
Sorry that i wasn’t clear in my question; i meant that i wanted the arms to move at the same speed in any framerate. This was the solution i came up with actually but then saw that the arms moved like this. Any advice?
Thanks for the response though, ill try to make it work in that way now
(Sorry if i’m bad at this, even though i speak english almost every day im still not good at it)

Yes, I know. Like I said:

Maybe try multiplying it by the DeltaTime instead? I know that I’ve done this before, it was just so long ago that I don’t remember anymore.

Also, I just now realized my idiocy. Maybe this?

local TIMES_PER_FRAME = 1/20 --how often you want to update the camera every second (20 in this case)
local SWAY_SPEED = 1 --the speed you want the arms to sway at (you'll want to mess around with this)

local camera = workspace.CurrentCamera

local CurrentTime = 0 -- a local variable for storing the current elapsed time value
local LastCameraCFrame = camera.CFrame

-- other code...

if arms.PrimaryPart then
	runService.RenderStepped:Connect(function(DeltaTime) -- sway
		CurrentTime += DeltaTime
		
		if CurrentTime >= TIMES_PER_FRAME then
			CurrentTime -= TIMES_PER_FRAME --you could also use the modulus operator here, but both would achieve different results in the event of noticeable lag over a duration
			
			local Rotation = camera.CFrame:ToObjectSpace(LastCameraCFrame)
			LastCameraCFrame = camera.CFrame
			
			local X,Y,Z = Rotation:ToOrientation()
			SwayCFrame = SwayCFrame:Lerp(CFrame.Angles(math.sin(X) * SwayEffect, math.sin(Y) * SwayEffect, math.sin(Z) * SwayEffect), SWAY_SPEED*DeltaTime)
			
			arms:PivotTo(LastCameraCFrame * SwayCFrame) --replaced 'SetPrimaryPartCFrame' because it has been superseded by  'PivotTo'
		end
	end)
end

If this doesn’t work please let me know. I can dig through my old projects to find the solution. Limiting the time it updates every second isn’t necessary, I just usually do that since any delay in the RenderStep can cause the rest of the loop to be delayed (especially because it’s the first).

1 Like

Don’t change the rate to a value above what is prudent. In the grand scheme of things, the arm animations don’t need to be updated every frame.

I changed the script a bit and now it works well

local SwayCFrame = CFrame.new()
local camera = workspace.CurrentCamera
local LastCameraCFrame = camera.CFrame
local SWAY_SPEED = 10 --the speed you want the arms to sway at (you'll want to mess around with this)

if arms.PrimaryPart then
	runService.RenderStepped:Connect(function(DeltaTime) -- sway
		local Rotation = camera.CFrame:ToObjectSpace(LastCameraCFrame)
		LastCameraCFrame = camera.CFrame

		local X,Y,Z = Rotation:ToOrientation()
		SwayCFrame = SwayCFrame:Lerp(CFrame.Angles(math.sin(X) * SwayEffect, math.sin(Y) * SwayEffect, math.sin(Z) * SwayEffect), SWAY_SPEED*DeltaTime)

		arms:PivotTo(LastCameraCFrame * SwayCFrame) --replaced 'SetPrimaryPartCFrame' because it has been superseded by  'PivotTo'
	end)
end

Thank you

1 Like