How to create code compatible with FPS Unlockers

French link: https://devforum.roblox.com/t/comment-creer-du-code-compatible-avec-les-fps-unlocker/1087900

Hello everyone, I’ve had the idea of creating a tutorial today on how to create scripts that would not cause unintended behavior if a player were to use a FPS Unlocker.

What does FPS stands for?

FPS stands for Frames Per Second, which corresponds to how often the image will refresh on the monitor.
Monitors have a refresh rate, which is basically the maximum amount of FPS the monitor can handle, the refresh rate of a monitor is usually one of these numbers:

30hz
60hz
120hz
144hz
240hz

The amount of frames per seconds an user can have depends on their hardware and on how optimized the game is.
Roblox locks the amount of FPS to 60 FPS, which means your screen will be limited to refresh the image 60 times a second.
There is a software that allows a player to “unlock” their FPS and remove that limit when playing a Roblox game, which is called a FPS Unlocker.

How does this help me as a scripter?

RunService has a few events that run every frame, RenderStepped, Stepped and Heartbeat. (Those three events will soon become deprecated and be replaced by PreRender, PreAnimation, PreSimulation and PostSimulation)
Those events all have a “delta” argument, which is the amount of time elapsed between the last frame and the current one, if you calculate 1/delta, it gives you the user’s FPS.

Let’s say you wanted to create a projectile that would move by CFraming, if I didn’t know how to use the delta argument, it would go like this:

local RunService = game:GetService("RunService")

RunService.Hearbeat:Connect(function()
    -- I know the maximum amount of FPS a player can have on Roblox is 60, therefore, the projectile will travel 100 studs in one second.
    projectile.CFrame = projectile.CFrame * CFrame.new(0, 0, -100/60)
end)

This is code I used to create before knowing about the delta argument, so what happened when I started using a FPS Unlocker? The projectile would fly off at a way greater speed than 100 studs/s.
There would also be the issue of players will mobile devices, who are not able to play at constant 60 FPS, the projectile would be slower for them.

If I want to fix this, I need to know how I can get the player’s FPS.
Delta is exactly that, 1/delta gives us the player’s FPS.
I can then modify my code above.

local RunService = game:GetService("RunService")

RunService.Hearbeat:Connect(function(delta)
    -- I could code -100/(1/delta) but it's simpler to just multiply by delta.
    projectile.CFrame = projectile.CFrame * CFrame.new(0, 0, -100 * delta)
end)

This code is going to make the projectile move at a speed of 100 studs a second, no matter what the client’s FPS is.
This means the projectile will move exactly 100/FPS studs every frame.

Link to a Roblox FPS Unlocker: GitHub - axstin/rbxfpsunlocker: FPS Unlocker for Roblox

20 Likes

One thing I don’t understand is their differences, there’s ONE extra one, and I am highly confused on what they do compared to RenderStepped, Stepped, and Heartbeat.

1 Like


The difference is when the event fires when the frame is being rendered, it depends on what you’re using it for.

2 Likes

Just to clear this up, the code will give the illusion that the projectile is moving at 100 studs, not at 100 studs. If the client is on 100 FPS, then the projectile will move 1 studs every Heartbeat, but since Heartbeat would be firing faster, it would give an illusion that the projectile is moving at 100 studs.

2 Likes

I modified it, thanks for noticing

How do you solve the issue, when players, especially players with low-end devices, have flickering FPS?
Recently I noticed that when I use studio, my FPS always flicker around 1 to 15.
This resulted in an awkward movement of the viewmodel that I scripted.

The only thing you can do is optimize your game.
Not all devices could be able to run your game.