This solution will allow your friend to keep using his fps-unblocker, without it being capped.
For example, take this piece of code, that moves a part 10 studs in the Y direction, across 20 frames:
local runService = game:GetService("RunService")
local camera = workspace.CurrentCamera
local part = workspace.Part
part.Position = Vector3.new(0, 20, 0)
local targetCameraPosition = Vector3.new(-20, 25, 0)
camera.CameraType = Enum.CameraType.Scriptable
camera.CFrame = CFrame.new(targetCameraPosition, part.Position)
local iterations = 0
local maxIterations = 20
wait(2) --Studio takes some time to load into client mode, so don't do it right away
runService.RenderStepped:Connect(function(deltaTime)
if iterations < maxIterations then
iterations += 1
part.Position += Vector3.new(0, 0.5, 0)
end
camera.CFrame = CFrame.new(targetCameraPosition, part.Position)
end)
This is what this code looks like at 24 FPS:
At 60 FPS:
At 144 FPS:
What you’ll notice is, as frame rate increases, the animation speed also increases. This is because there is less time between frames. There will also be cases where players will have framerates below 60FPS, in this case, it is going to cause animations to be slower for them, which will make the user experience worse.
The good thing is, every frame an argument is passed through RenderStepped, called Delta
, what this tells us is the time that it took between the last frame and the current frame. This is also called Step
, or shortened to s
in some scripts. For a player who’s running at 24 FPS this will be approximately 1/24th of a second or 0.04166..s
, for a player who’s running at 60 FPS it will be approximately 1/60th of a second, or 0.0166..s
, and at 144 FPS, it will be approximately 0.006944...s
. This will be useful to you as a programmer, as it essentially tells you what fraction of a second has passed, and you can adjust how fast animations happen as a result.
You can read more here:
What this means is, if you wanted to move a part 10 studs, within 1/3rd of a second, you’d say 10 studs * (delta / 1/3 seconds)
, which will move the part the correct amount within the specified time, so that no matter what framerate the player is on, it will look smooth, and will have exactly the same speed.
Here is some example code, which utilizes the Delta
argument:
local runService = game:GetService("RunService")
local camera = workspace.CurrentCamera
local part = workspace.Part
part.Position = Vector3.new(0, 20, 0)
local targetCameraPosition = Vector3.new(-20, 25, 0)
camera.CameraType = Enum.CameraType.Scriptable
camera.CFrame = CFrame.new(targetCameraPosition, part.Position)
local studsToMove = 10
local timeToComplete = 3
wait(2) --Studio takes some time to load into client mode, so don't do it right away
local studsMoved = 0
runService.RenderStepped:Connect(function(deltaTime)
if studsMoved <= studsToMove then
local targetStudsToMove = math.min(
studsToMove - studsMoved,
studsToMove * (deltaTime / timeToComplete)
)
part.Position += Vector3.new(0, targetStudsToMove, 0)
studsMoved += targetStudsToMove
end
camera.CFrame = CFrame.new(targetCameraPosition, part.Position)
end)
This is what it looks like at 5 FPS (for exaggeration):
This is what it looks like at 60 FPS:
This is what it looks like at 144 FPS:
You’ll notice that they look exactly the same speed regardless of framerate.
This is the way to go.
Please do not listen to other advice to cap the framerate. It is bad practice.
If you need any specific advice on how to handle delta or frame times, do not hesitate to PM me. I’ll always be willing to be a helping hand .