Hello, I am making a timer but I’m not sure which kind of loop would be generally the best to use for a timer that can be stopped at anytime.
sorry I typed this on mobile
—while loop
local run = true
local debounce = tick()
local Time = 0
while true do
if run == false then —timer stops if run is false
break
end
if tick() >= debounce +1 then — checks if current time is greater than debounce plus a second
debounce = tick() — changes the debounce to the current time
Time += 1
print(Time)
end
end
—runserivce loop
local RunService = game:GetService(“RunService”)
local debounce = 0
local Time = 0
local function func()
debounce +=1
if debounce == 60 then — if debounce is 60 then it resets it
debounce = 0
Time += 1
print(Time)
end
end
local connection = RunService.Heartbeat:Connect(func) — to start the heartbeat function
connection:Disconnect() —to stop timer from running
the while loop uses tick as the cooldown and the runservice relies on every 60th frame
So in your opinion which one do you prefer the most?
It depends on your script/situation. Plus, if you’re using While loops, please avoid using ‘Wait’ and use either runservice or task.wait(), they’re much better and more efficient.
I don’t see a wait function call in the while loop, doesn’t that freeze the game?
Second of all, you’ll never need a while loop with a wait function inside it. Otherwise just use RunService’s events. Each event is for a specific purpose, and they’re all synced with the engine internals.
For example RenderStepped is called before rendering the scene, Heartbeat is called after simulation, Stepped is called before physics step.
For example:
Use Heartbeat for most frame to frame logic
Use Stepped to change physics stuff
Use RenderStepped for Camera movement
Find out more here: Task Scheduler (roblox.com)
Otherwise I only use while loop as a substitution for the for loop when how much steps the loop have to run isn’t clear.
local timerID = 0
local function StartTimer(duration, callback)
timerID += 1
local currentTimerID = timerID
delay(duration, function()
if currentTimerID ~= timerID then return end
callback()
end)
end
local function StopTimer()
timerID += 1
end
StartTimer(10, function()
print("This will never be called because we stoped it")
end)
-- stop the previous timer
StopTimer()
StartTimer(10, function()
print("This will never be called because we started another timer after this timer")
end)
-- overwrite the previous timer
StartTimer(10, function()
print("Hello World")
end)
The only issue with this is that the timer is only as accurate as the wait() method which isn’t that accurate. That’s why they replaced it with task.wait() which runs off heartbeat. In that case why not just connect your timer to heart beat? Probably less effort too.
I typically do something like this for a timer:
local someTimer = tick() + 5 --5 sec timer
game:GetService("RunService").Heartbeat:Connect(function()
if(someTimer <= tick())then
print("Times Up!")
someTimer = tick() + 5 --reset the timer.
end
end)
but that’s only when you call wait many times over and over but if you only call it once then the accuracy is not that bad
for instance lets say every time you call wait(1) instead of waiting 1 second it might wait 1.01 seconds
so if you have
while true do
wait(1)
end
so as each time you wait it may add 0.01 seconds more so it adds up over time
and after its waited a total of 100 times it might be out of sync by 1 hole second
but if you only call wait once like this
wait(100)
then it might wait 100.01 seconds and that’s not that bad
You should not use RunServer (RenderStepped, Heartbeat, …) to make a timer. In general RunServer should be used only if necessary (as the documentation above says) and a timer does not require so much precision.
For a timer it is typical to use tenths of seconds (0.3s, 0.2s, 0.1s). Smaller numbers would simply not be appreciated by anyone. RunServer’s accuracy is about 0.01666667s (1/60). An unnecessary waste of a valuable resource such as RunServer.
With task.wait() creating a fixed time game loop is as simple as this:
while true do
task.wait(0.3)
--your code
end
Note that you don’t need to use tick() or os.clock() either.
I’m sorry, but I don’t understand what you are saying. In the documentation it does not say that it is using or is implemented with Heartbeat.
It says there that the thread that was paused by task.wait() is resumed on the next Heartbeat, that is, after the physics simulation, unlike wait(), but which is equivalent to Heartbeat.
Anyway, it would be somewhat strange (and disappointing) if task.wait() was just a macro for Heartbeat without any internal optimization.
If the thread halted by task.wait() resumes on the first heartbeat step after the duration has elapsed, then even if it doesn’t use heart beat itself the result is effectively the same.
In the task scheduler docs it specifies this guideline only for render step and immediately afterward says this:
I see your point, but it’s not effectively the same thing. With Heartbeat a thread is resolved at each step of the game, whereas with task.wait() only one thread is resolved when the time is up.
I think RunService because the while loop is going to loop needlessly sometimes. So it’s probably going to use more CPU where the Roblox event should be only getting run when needed. The RunService snippet is probably also better for readability.