How to make a for loop happen for a specific amount of time with a custom wait time?

The title is pretty self explanatory. When trying to solve myself, this was what i tried.

local duration = 5
-- how long to record for

local capture_rate = 10
-- the framerate of the recording. 

task.spawn(function()
-- the actual for loop happens here.
	for i = 0, (duration*capture_rate) do
		print("time taken: "..i/capture_rate)
		task.wait(1/capture_rate)
	end
	print("done")
end)

-- this is a benchmark to check if the for loop had actually happened for 5 seconds
task.spawn(function()
	task.wait(duration)
	print("benchmark done")
end)

Even though the math seems correct, the for loop fires much slower than the actual seconds taken.


Does anyone know what i had done wrong, and if there are alternative ways to achieve the same thing?

I believe you should do i = 1 and not i = 0 since Lua is pretty whacky in that 1 actually equals 1 unlike most coding languages where 0 is usually equal to 1.

Also gonna point out, a task.wait(1) doesn’t actually wait 1 second, it just waits as close as it can to 1. You can easily check this by doing this in the command bar:

local time1 = os.clock()
task.wait(1)
local time2 = os.clock()
print(time2-time1) -- prints out how long it actually waited

What it prints out would probably be close to 1 but not actually 1. Currently not in studio to test this out.

There’s also the fact that code runs 1 line of code before the next so you doing a print("time taken: "..i/capture_rate) then a task.wait(1/capture_rate) makes the wait a bit longer. More time is also spent doing the math calculation for 1/capture_rate so you should probably convert that into a variable that’ll be reused. Also gonna note, the time waited is practically unnoticeable for a person, so you should generally not worry about how long it takes for some code to run.

And one final thing, this goes into Parallel Programming which is a bit complicated so I’ll try to keep it short. task.spawn() doesn’t actually create a “2nd script” I guess. It’s more just lettings parts of other code to be run, then runs is own code, then runs the other parts of code and so on. What does it have to do with the task.wait() well as stated before, code runs basically 1 by 1, the more code you have the more wait it’s doing I guess. Also gonna repeat myself to make this clear, you should generally not worry about how long it takes for some code to run. The only time you should is when you’re doing like some sort of super hard math calculations for movement or something.


Anyways how do we fix your problem? Well you could just wait for the loop thing to complete then do your code:

for i = 0, (duration*capture_rate) do
	print("time taken: "..i/capture_rate)
	task.wait(1/capture_rate)
end
-- do your other stuff here

But if you for some reason can’t do that then you can make a custom signal either a BindableEvent or use a module like GoodSignal (way more complicated but has better performance, really should only be used if you’re making a module that’ll be used by other people or if you’re smart enough to use it) that runs after the code is done looping then connect a function to that signal that does whatever you’re doing.:

local LoopEnded = BindableEvent -- or something idk

task.spawn(function()
	for i = 0, (duration*capture_rate) do
		print("time taken: "..i/capture_rate)
		task.wait(1/capture_rate)
	end
	LoopEnded:Fire()
end)

LoopEnded.Event:Connect(function()
	print("Ended")
end)

All in all, you are doing nothing wrong, you just can’t do what you’re asking for due to how code is ran, you can only get close to it. At least, as far as I know : P

Putting the wait in a seperate script still leads to the same 1 second delay between the for loop and task.wait(). even though task.wait() does not wait exactly the time i want it to, it can still get pretty close.

This is similar to how you would do it in unity. This loop runs every frame and checks if the interval has passed to run again, its the most accurate, it also breaks when done.
Example code:

local timeBetweenFrames = 0.1
local totalTime = 5
local nextRunAt = 0
local startTick = tick()

local Connection
Connection = game:GetService("RunService").Heartbeat:Connect(function(DT)
     if (tick() - startTick) >= totalTime then
          Connnection:Disconnect()
     elseif (tick() - startTick) >= nextRunAt then
          nextRunAt += timeBetweenFrames
          print("Do stuff here")
     end
end)
1 Like

this was such a simple solution i’m surprised i never thought of this! thank you so much!

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