When wait() is called with no parameter, it waits for about 1/30th of a second, which is the minimum amount of time that wait() can yield.
Although the wait function is guaranteed to yield for at least the inputted amount of time, you shouldn’t count on it waiting for that exact amount of time. Luckily, the function returns the actual time yielded, which you can use to account for that.
If you plan on using wait() in while loops it might be a better idea to use RunService.Heartbeat:Wait()
instead.
The Heartbeat
event fires on a variable frequency so there is always a chance of some noise, but under ideal conditions it happens about 60 times per second, so if you were to implement a custom wait function using Heartbeat, it would have a minimum of about 1/60th of a second rather than the wait() function’s 1/30th of a second.
You could also bind your loop logic to the event as an anonymous function, removing the need for an infinite loop altogether.
local rate = 10 -- 10 HP/sec
while (HP < 100) do
HP = math.min(100, HP + rate / 30)
wait()
end
In this example, an assumption is made that the loop will run at a frequency of 30hz. This code will work, but the timing may not be as precise as you expect.
local rate = 10 -- HP/sec
while (HP < 100) do
local dt = wait()
HP = math.min(100, HP + rate * dt)
end
This example accounts for the amount of time yielded when the wait() function was called, causing the HP value to rise at a more steady and precise rate.
local rate = 10 -- HP/sec
local conn
conn = game:GetService("RunService").Heartbeat:Connect(function(dt)
HP = HP + rate * dt
if (HP >= 100) then
conn:Disconnect()
end
end)
This example accounts for the difference in time between this physics frame and the last physics frame (by multiplying the rate by the time difference). Since it also uses an event rather than a loop, it doesn’t yield the script either.