The idea of using a Heartbeat is to ditch the loop. Heartbeat is much more precise than a loop since it always fires each frame, unlike a loop where you have to yield it using an imprecise method like wait
-
All of the code that needs to be run constantly needs to be there, since this is essentially your “new loop”.
You have 3 different variables here:
local roundTime = 600 --Controls how much time the round has left
local completedStates = {} --Stores all states that were completed
local states = {} --A table that contains the different states for your round
local roundConnection = nil --Keeps track of the current connection; YOU NEED TO KEEP TRACK OF IT TO STOP IT WHEN THE ROUND IS DONE
completedStates
simply makes sure that you’re not calling the same states again.
Each key in states
represents a different time period, and their value is a function to be called when the current time is equal or less to that period. Why do we have to check if it’s less than? It’s simple, since the time of each frame can vary, the time period will most likely not be exactly the same as the time period you have defined.
For what you’ve asked in the OP, states would look something like this:
states = {
[590] = function() print("I'm called when a player needs to be teleported!") end)
[0] = function() print("I'm called when the round ends!") end)
}
Now, the most important part is actually setting up the loop!
function module.StartFFGRound(length, chosenMurderer, map) -- in seconds
--Clean-up previous round data
roundTime = 600
completedState = {}
roundConnection = RunService.Heartbeat:Connect(function(dt)
roundTime -= dt
for timePeriod, functionToCall in pairs(states) do
if roundTime <= timePeriod and not completedStates[timePeriod] then
functionToCall() --Call the function needed (You can also parse any arguments if you need them in the function)
completedStates[timePeriod] = true --Mark this state as complete
end
end
end)
end
The loop code is surprisingly not that hard. It simply reduces the delta time from the round’s time each frame, and then for every existing state, check if the state’s time period is less than or equal to the current round’s time and if it hasn’t been called before. If the check passes, then call the associated function and set the state as completed, so it can’t be called again.
Finally, you have to do the cleanup, this can be easily made with the function you assign the number “0” to, since it’ll run when the round ends.
function()
roundConnection:Disconnect() --Stop the code you bound to heartbeat from executing, since the round is over.
roundConnection = nil --Let the connection be garbage collected by Lua (eliminated)
end
This simply stops the round code from running after it’s over.