One second delay after timer countdown ends

Hello everyone!

For some reason, when I finish a countdown (such as the one for intermission), the “Phase: Round” string comes in one second early, and not when the round countdown begins.

Here’s the script I’m using:

local roundLength = 240
local intermissionLength = 10

local replicatedStorage = game:WaitForChild("ReplicatedStorage")
local roundPhase = replicatedStorage.RoundPhase
local roundTimer = replicatedStorage.RoundTimer
local inRound = replicatedStorage.InRound

local gameTeleports = game.Workspace:WaitForChild("GameTeleports")
local lobbySpawn = gameTeleports.LobbyAreaSpawn
local mapSpawn = gameTeleports.MapAreaSpawn

local secondsDisplay = ""
local minutesDisplay = ""

 local function phase()
while wait() do
	for i = intermissionLength, 1, -1 do
		roundPhase.Value = "Phase: Intermission"
		inRound.Value = false
		wait(1)
	end
	for i = roundLength, 1, -1 do
		roundPhase.Value = "Phase: Round"
		inRound.Value = false
		wait(1)
	end
end
end

 local function timer()
while wait() do
	for i = intermissionLength, 1, -1 do
		roundTimer.Value = "0:" .. string.format("%002d", i)
		wait(1)
	end
	for i = roundLength, 1, -1 do
		local seconds = 59
		local minutes = 3
		local secondsDisplay = ""
		local minutesDisplay = ""
		for m = minutes, 0, -1 do
			if m < 10 then
				minutesDisplay = m
			else
				minutesDisplay = m
			end
			for s = seconds, 0, -1 do
				if seconds > 59 then
					s = 59
				end
				if s < 10 then
					secondsDisplay = "0"..s
				else
					secondsDisplay = s
				end
				roundTimer.Value = minutesDisplay..":"..secondsDisplay
				wait(1)
			end
		end
	end
end
end


spawn(phase)
spawn(timer)

Anyone see what’s up?

The order in the countdown loops are wrong. Place the wait(1) at the top instead like this:

wait(1)
roundPhase.Value = "Phase: Round"
inRound.Value = false

I don’t know if I understand, but try this:

for i = intermissionLength, 1, -1 do
    if i == 1 then
        roundPhase.Value = "Phase: Intermission"
        inRound.Value = false
    end
    wait(1)
end

Sadly, even when I do this in a script, there’s still a one second delay except it’s after. Any other ideas?

Okay, this is because you are using two different counters. Inside the intermission loop you want to check if the intermission is over. If it is, you set up the Round phase.

Either way it will wait one second as it’s on the last loop.

Code runs on Roblox via in threads, threads that encounter halts such as waits or loops or any code in general that takes time, will briefly prevent any code from being processed below said halt. take a look into

Ah, ok. Should I not worry about this fraction-of-a-second wait time?

You’re saying it’s a fraction-of-a-second now, but it was a full second before.

Is it genuinely a full second or a fraction?

You should always worry about time while programming anything.

I worry about it more than bugs.

I figured out that I shouldn’t put the wait() on top or bottom, but in the middle. It’s eliminated the full second wait time but now it’s very minor, about 0.2 of a second.

My apologies for not clarifying sooner.

wait()

on the server is around 1/20th of a second usually

and

wait() on the client

is about 1/60th of a second usually

Thank you for bringing this code smell to light; didn’t even notice it was one.

I replace wait() with true and the fraction-of-a-second is gone. Thanks guys!

You should set his reply as the solution, not your own.

In other news, you should probably move away from spawn and not have two functions that do exactly the same thing but in different threads, especially when you’re feeding that into spawn. You can do that work all from a single function for updating time to make things consistent.

For the way you evaluate round time in the round loop, that’s a pretty old way of doing it. The proper, best and most accurate way to do that is to count seconds and format them accordingly into MM:SS format where minutes is a floor round division by 60 and the seconds are raw modulus by 60.

for i = roundLength, 1, -1 do
    local minutes = math.floor(i/60)
    local seconds = i%60

    roundTimer.Value = ("%d:%02d"):format(minutes, seconds)
    wait(1)
end

The following counter above will not reach 0:00. For that to happen, your second expression must be 0, not 1, so it loops from roundLength to 0. That is probably what you intend in both cases.

For a start it’s not bad but ideally in the end you only want a single round loop since these processes belong with each other, rather than having them separate and trying to synchronise them with no predictability and now with spawn, guarantees that they’ll actually run.