Keep task.wait() speed the same across frame rates?

I was reading this article about the new maximum frame rate update, I was trying to figure out how to make my client scripts have the same speed regardless of the frame rate. I was successful in parts of the code where I handle in the RunService because I just had to multiply with DeltaTime. But outside of RunService how would I keep the task.wait speed the same?
My first idea was to do this:

while true do
	if isFiring and Config.Ammo > 0 then
		local Connection
		Connection = RunService.Heartbeat:Connect(function(delta)
			Shoot()
			wait(Config.FireDelay*delta)
			Connection:Disconnect()
		end)
	end
	wait()
end

But I am pretty sure this would be pretty slow compared to alternatives (if they exist) as well as just ugly code.

1 Like

I might be misunderstanding the question, but task.wait(t) waits for ‘t’ seconds, then resumes execution the next time user code can run. No changes should be necessary.

If you mean task.wait() without t, just fill t in as 1/60 which should be about what it was before. Since task.wait() without a time value will execute at the next opportunity. (Also you should use task.wait for new code instead of wait)

I’m not sure why you’re using wait(t) instead of task.wait(t), but wait() is not the same as task.wait(). wait() is tied to the framerate, while task.wait() isn’t. Also, if you’re using a deltatime, task.wait() will return the deltatime to you.

It’s a client sided script and yeah task.wait(t) in this case Config.FireDelay

Originally I was using task.wait() I just changed it to wait() to see if it would make any difference while I was debugging and just forgot to switch it back.

Switched it back to task.wait() it still has a small increase in speed when switching to 240 FPS.

while true do
	if isFiring and Config.Ammo > 0 then
		Shoot()
		task.wait(Config.FireDelay)
	end
	task.wait()
end

When the refresh rate update came out, I too had to change how my loops using task.wait() worked. After the update they were tied to the maximum framerate (e.g. 60fps or 240fps), so at 240fps my things played through at about 4x the speed of 60fps.

To combat this, I instead did something like this:

local elapsed = 0 -- OUTSIDE THE LOOP
local length = 1 -- LENGTH IN SECONDS

while elapsed < length do
 elapsed = math.min(elapsed + task.wait(), length) -- wait a single frame, add to the elapsed time the time the frame took to wait, caps at length
 
 local percent = elapsed / length -- a value between 0 and 1, 1 being the end of the time length specified
 
 -- YOUR CODE HERE USING percent
end

Also, I did forget to mention that a specified time value inside task.wait(t) will never be tied to the framerate and will be guaranteed to wait your specified amount of time (t).

On the other hand, however, even with a provided t value, wait(t) will be tied to the framerate, hence why it’s been deprecated and shouldn’t be used anymore. It also appears that wait() is capped at 60fps.

Fill in a time. They both fundamentally check if ‘t’ seconds has passed and schedule the code to run again at the next opportunity once t has elapsed.

Set a frame rate you want to be the base like 60 then task.wait(1/60). Now it will act mostly like it’s a 60fps wait.

2 Likes

The only problem with this is that if you want it to run at the target refresh rate, this method will not run at that framerate, effectively locking the loop to 60fps.

Now, for a lot of things, that’s completely okay! For this code example, that is probably the best thing to do!

That is true. In most cases if you want to perform work so quickly it’s best to do a heartbeat or some other run service binding. I’m pretty sure a task.wait() is almost identical to a rs.Heartbeat:Wait() if you don’t fill a time

2 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.