Waiting 1/60th of a second in the new framerates

I made this function that wait’s 1/60th of a second. Are there any better or more standard functions I can use to achieve the same goal?

local RS = game:GetService("RunService")
local TargetFramesPerSecond = 60

local function WaitFPS()
	local sum = 0
	repeat
		local dt = RS.RenderStepped:Wait()
		sum+=dt
	until sum >= 1/(TargetFramesPerSecond +5)--Add 5 so that it wont wait an extra time if the sum is just under 1/60 (most noticeable when game is set to a low framerate)
	return sum
end

while wait(1) do
	print(WaitFPS())
end

You lose the approximate wait time (close to 1/60), but that really isn’t a problem.

local TargetWaitTime = 1/60
task.wait(TargetWaitTime) -- defaults to 1/60 anyways, but I'm not sure about higher FPS
1 Like

local Desired = task.wait(1/60)
It will wait at least 1/60 of a second.
So simple yet so functional…

3 Likes

Personally there isn’t really any benefit to this. It just seems like an excuse to not use delta time when working with game loops.

It is meant to replace Renderstepped:Wait()
Yes it is an excuse to not use deltatime
I don’t really want to rework the entire script, so this seems to be a nice patch.
How the script works is that it does a thing, then waits for the next frame and does something else then, and repeat. So I don’t really want to change everything to make deltatime work.
Nothing is more permanent than a temporary solution that works.

I find this waits seemingly a bit too long, idk why. I am working with precise tween animations, so getting the animation to play every frame for a 60 fps game is imperative. I can use the animation editor but that would take a lot of effort for something that may not help.

The canonical way is to add the DeltaTime and check if it is above your intended rate.

local Rate = 1 / 60
local Time = 0

local function OnPreRender(DeltaTime: number)
	Time += DeltaTime
	
	if Time > Rate then
		Time = 0
		
		print("Runs at MOST every 60th of a second")
	end
end

If you are working with interpolation, you should multiply the Alpha by the DeltaTime and your desired rate and clamp it under 1. This makes sure that you interpolate uniformly regardless of the framerate, but never too much.

local Rate = 1 / 60

local function OnPreRender(DeltaTime: number)
	local Result = Origin:Lerp(
		Goal,
		math.clamp(0.1 * DeltaTime * Rate, 0, 1)
	)
end

use task.wait instead of wait
wait is old, and can only wait a minimum of 1/30th of a second
on the other hand, task.wait is not throttled, and is only limited by fps (e.g. if game’s at 60 fps, task.wait() and task.wait(1/60) waits 1/60th of a second. if game’s at 120 fps, task.wait() waits 1/120 seconds, and task.wait(1/60) waits 1/60 seconds. game at 30 fps, task.wait() and task.wait(1/60) waits 1/30th of a second)

I dont think this is entirely true. task.wait() is better than wait. However I ran an experiment and found task.wait() and task.wait(1/60) do not wait for the same time at 60 fps. The same experiment found that RS.RenderStepped and task.wait() waited for the same amount of time. From this data I can’t explain why I found my animation playing slower in my game using task.wait(), I might have used task.wait(1/60). I think there is a negligible difference between task.wait() and RS.RenderStepped:Wait().

task.wait should run on the same interval as Heartbeat/PreSimulation, not RenderStepped/PreRender. The server doesn’t even have a render task.

What exactly are you doing that must be ran every 60th of a second?

I have an old gun script with custom arms and custom animations for them. This was made back when 60 fps was the standard and max. Running the script at more than 60 fps makes the animations run too fast. Since I dont know too much about animation, I would rather force the custom interpolater and animation controller to run 60 times per second than figure out how to change it so it works with deltatime. Which may require a total restructuring of the entire 2000 line long script.
The client also does not have access to Heartbeat, so I can’t use that.

Use RenderStepped then. Similar functionality.

Use RunService.Heartbeat:Wait() Directly

local RunService = game:GetService("RunService")
local TargetFramesPerSecond = 60
local TargetTime = 1 / TargetFramesPerSecond

local function WaitFPS()
    local dt = RunService.Heartbeat:Wait()
    while dt < TargetTime do
        dt = dt + RunService.Heartbeat:Wait()
    end
end

while true do
    WaitFPS()
    print("Frame passed")
end

Use task.wait()

while true do
    task.wait(1 / 60) -- Waits approximately 1/60th of a second
    print("Frame passed")
end

Use RenderStepped for Gui and Camera Updates

local RunService = game:GetService("RunService")

RunService.RenderStepped:Connect(function(deltaTime)
    if deltaTime >= (1 / 60) then
        print("Frame passed")
    end
end)
1 Like

animations always look either like

Weld.C0 = clerp(Weld.C0, TargetCFrame, Alpha)

OR

Weld.C0 = Weld.C0:Lerp(TargetCFrame, Alpha)

to fix for 60 fps, just do

RunService.RenderStepped:Connect(function(deltaTime)
    Weld.C0 = Weld.C0:Lerp(TargetCFrame, Alpha * math.clamp(deltaTime * 60, 0, 1.25))
end)

for stuff like

step = step + 1

or

sine = sine + 1

just change the 1 to deltaTime * 60

and voila, it looks the same as 60 fps
if anims are done on the client, there’s the bonus of looking smooth on higher framerates