(problem) wait() not being 100% accurate

Hi, I’m struggling a lot with wait() not being 100% accurate for the cooldowns for some skills in a project of mine. I ran a test and it proved that wait() is pretty inaccurate.

in a for loop:

local Cooldown = 10
local start = time()
wait(Cooldown/20)
print(time() - start)

Output:

  0.51250002766028
  0.51666669454426
  0.51666669361293
  0.50000002607703 (x2)
  0.51666669361293 (x3)
  0.50000002607703
  0.51666669361293

This is a big problem as the cooldowns need to be accurate for the player. Is there a method to wait a specific amount of time 100% accurately?

It is not possible to wait exact amounts of time. wait(n) is the same as just calling wait() a bunch of times in a row until n seconds have passed, and the actual amount of time elapsed will always be at least n. You can use other yielding functions that are faster than wait, though, to time things slightly more precisely.

1 Like

Yup, wait(n) will wait at least n seconds. You should try using RunService.Stepped:wait() or RunService.Heartbeat:wait() as they are faster and supposedly more reliable.

Here’s a good post about your issue: Avoiding wait() and why

3 Likes

@1waffle1 @mario118118 Thank you, I’ll start using .Stepped for things like this and hopefully get better results.

No, that post talks about wait(), not wait(n), which is what is being used here. Also no, don’t use Stepped:wait() or Heartbeat:wait() for this since you’d just need to end up looping more for no reason.

Your problem isn’t wait(n), this behavior is expected. Your problem is you’re handling cooldowns by yielding, which is not a good way of doing it. You could better handle cooldowns (and have them be exact) by simply marking when an ability is used by logging the time using tick(), and comparing that time afterwards when the player attempts to use it again.

For example;

local cooldown = 0 -- start at 0 so it works right away

local function do_thing()
    if tick() < cooldown then
        return -- guard
    end
    cooldown = tick() + 0.5 -- sets the debounce to 0.5 seconds in the future
    -- your code would go here
end

This is a concept example, but it’s probably the most accurate way to do this.

10 Likes

It would be easier to make a cooldown using tick() or time(), as they would be more accurate, and will not require you to depend on wait.

local cooldown = 0 --Keep track of last used time
local timeToWait = 10 --Seconds to wait before re-activating
local function useAbility()
    cooldown = tick() --Resets cooldown
end
local function isAvailable()
    return tick()-cooldown >= timeToWait
end

--Now, whenever a user clicks a key to activate it:
if isAvailable() then
    useAbility()
    --Do cool effect
end
3 Likes

Ah that’s pretty neat, it also gave me quite a handful of ideas! Thank you very much! :slight_smile:

Glad I could be helpful. Just remember, waits will never be fully accurate. It’s better to use tick() or os.time() to get the current time and check it to previous results.