This is a small and easy to use module that makes it easier to create 2 different types of loops.
Time Distribution
This will fire a function x number of times over y number of seconds. The function will return a RBXScriptConnection
, and calling :Disconnect()
on the connection will stop the loop from running
local LoopUtil = require(game:GetService("ReplicatedStorage"):WaitForChild("LoopUtil"))
-- Fire this function 100 times over 3 seconds
local Connection = LoopUtil.TimeDistribution(3, 100, function()
print("Fire")
end)
-- Stop running after 1 second
task.delay(1, function()
Connection:Disconnect()
end)
Interval
This will fire a function every x amount of seconds without accumulating time error like in a normal while true do wait()
loop. If the interval is less than the frame time, it will fire the function multiple times in a single frame so the time between function call could be different. This function also returns RBXScriptConnection
object and calling :Disconnect()
on it will stop the loop from running
local LoopUtil = require(game:GetService("ReplicatedStorage"):WaitForChild("LoopUtil"))
-- Fire this function every 2.5 seconds
LoopUtil.Interval(2.5, function()
print("Fire")
end)
-- Fire this function 250 times every second
local Connection = LoopUtil.Interval(1/250, function()
print("Fire")
end)
-- Stop running after 1 second
task.delay(1, function()
Connection:Disconnect()
end)
Source Code
This should be copy and pasted into a ModuleScript
and placed where ever you need it
local RunService = game:GetService("RunService")
local Module = {}
local function GetIterationsDue(StartTime, Time, Iterations)
return if (Time > 0) then math.floor(Iterations * math.clamp((os.clock() - StartTime) / Time, 0, 1)) else Iterations
end
function Module.TimeDistribution(Time: number, Iterations: number, Function: () -> nil)
local StartTime = os.clock()
local IterationsDue = GetIterationsDue(StartTime, Time, Iterations)
local IterationsFired = IterationsDue
if (IterationsDue > 0) then
for Key = 1, IterationsDue do
task.spawn(Function)
end
end
if (IterationsFired >= Iterations) then
return
end
local UpdateConnection; UpdateConnection = RunService.PreSimulation:Connect(function()
IterationsDue = GetIterationsDue(StartTime, Time, Iterations)
if (IterationsDue > IterationsFired) then
for Key = 1, IterationsDue - IterationsFired do
task.spawn(Function)
end
IterationsFired = IterationsDue
if (IterationsFired >= Iterations) then
if (UpdateConnection) then
UpdateConnection:Disconnect()
UpdateConnection = nil
end
return
end
end
end)
return UpdateConnection
end
function Module.Interval(Interval: number, Function: () -> nil)
local StartTime = os.clock()
local IterationsDue = 0
local IterationsFired = 0
return RunService.PreSimulation:Connect(function()
IterationsDue = math.floor((os.clock() - StartTime) / Interval)
if (IterationsDue > IterationsFired) then
for Key = 1, IterationsDue - IterationsFired do
task.spawn(Function)
end
IterationsFired = IterationsDue
end
end)
end
return Module