How to Make a Wait Without Pausing the Whole Script Under

I don’t believe anybody asked for this, but I always find it annoying that I have to reconfigure a whole script just so this one wait doesn’t pause the thread under- but I have a problem with a script I’m using, so I came up with a solution.

The script would pause the while loop at the bottom of my script, and I can’t put the code under the loop or the other code won’t run! So, I came up with a larger, but better solution.

And yes, I do know I could move the while statement to another script, but I like keeping everything in 1 LocalScript and 1 ServerScript (if needed).

How to use it

Instead of doing this (example):

wait(1)
-- some code that uses a wait

while wait() do
-- some code that should always be running even when in a wait and is too fast when using a Heartbeat statement
end

Do this (example):

local t = tick()
timer = game:GetService'RunService'.Heartbeat:Connect(function()
   if (tick()-t) < TIMETOWAIT then return end
   -- some code that uses a wait
   timer:Disconnect() -- stop the code from rerunning
end)

while wait() do
   -- some code that needs to be always running and now can because it doesnt have a wait() at the top :D
end

How it works!

Pretty much it does this:

- local t = tick() Gets the time from January 1st, 1970 to now and puts it into a variable called t

- timer = game:GetService'RunService'.Heartbeat:Connect(function() Creates a thread of RunService’s Heartbeat (Can also use RenderStepped I think) and puts it into a global named timer

- if (tick()-t) < TIMETOWAIT then return end This then gets the new time from January 1st, 1970 to now and subtracts it from the original to get the amount of seconds since the t variable was created and compares it with a < to the amount of seconds you’d like it to wait() for and if its not past, it’ll return and not run the rest of the code.

- -- some code that uses a wait Just replace this with your code lol

- timer:Disconnect This stops the thread from running again so it doesnt make the code run over and over again, which would be very bad.

- end) Finishes off the function !

Conclusion & Poll

Please note: This is my first tutorial on here, please don’t judge that its basic.

If you think you might use this, please vote that in the poll below! If not, vote otherwise :]

  • I won’t use this
  • I might use this in the future
  • I’ll use it at some point.

0 voters

Thanks for reading!

1 Like

You can avoid this issue altogether by placing things that should run asynchronously in their own coroutines.

Coroutines also look more elegant as you aren’t relying on more services or timer variables.

9 Likes

hmm, your right. i really should have done more reasearch before making this

oh well ;(

@Autterfly already said so, but you can also use delay or make a coroutine to achieve the same behavior, and in a more efficient way too:

delay(1, function(waitTime)
	-- code that uses wait
end)

while true do
	wait()
	-- looped code
end
coroutine.wrap(function()
	local waitTime = wait(1)
	-- code that uses wait
end)()

while true do
	wait()
	-- looped code
end

And you can actually create the loop first with an event connection to RunService!

local RunService = game:GetService("RunService")

local loopConnection = RunService.Heartbeat:Connect(function(deltaTime)
	-- looped code
end)

local waitTime = wait(1)
-- code that uses wait

Yeah I tried the RunService solution but my code made my Loader spin way too fast and since it is based off of FPS, you can’t really use it unless you arent using any math things

I’m not going to change my code to use coroutine or delay because my code still works, but in the future I’ll look into it :wink:

1 Like

Use the deltatime argument recieved and spin it based on that.

ElapsedTime += deltaTime – delta time is time from last frame

CurrentRotation = ElapsedTime * RotVelocity

2 Likes

Cases where you need to run code asynchronously are where Promises shine. If you don’t need everything that Promises provides you with or it’s too much for your flow, then a coroutine alone would suffice here. This tutorial pretty much… ignores both of those things, when they’re your best solutions.

You effectively don’t need anything from this tutorial if you just use one of those two things. I don’t think this is the right kind of thing to be covering in a tutorial since there’s already given methods of running code without pausing subsequent code underneath.

This is good advice for those who use while-do loops. I personally keep my code asynchronous using Events, but on the odd occasion where I do need an infinite loop, this is usually similar to the method I’d use.

My general thinking when I make my game scripts is “keep things abstract,” and “worry about the future in the future.”

P.S. You seem to have made a typo in your example:

“Heartbeat” is not a game service. It is an Event of RunService:

game:GetService("RunService").Heartbeat:Connect(function()

This part of your script is incorrect.

Ah, yeah. Meant to fix that while adding the “how to” forgot, sorry! It should be fixed in a minute. ;w;

i feel really stupid lol

i REALLY should do more search on stuff :frowning:

The delay function runs on 30Hz, meaning the time you wait will not be accurate by around 1/30th of a second, coroutines have a few problems too where you cannot easily get the result of a coroutine.

Your example is what you would call a custom delay function, it allows you to delay and run code without stopping the script.

I actually use the Heartbeat function to run code without stopping the whole script.

No worries, this was clever ^^

1 Like

lol yeah just use coroutines, don’t use spawn() though because 1 it’s deprecated and 2 it’s really, really bad. Coroutines V.S. Spawn()... Which one should I use? - #8 by evaera