Countdown is not exact

My seconds in my countdown scripts go slower that the actual seconds go. I tried adding deciseconds but that didn’t help. I tried even milliseconds but still no luck.

local timer = script.Parent
local minutes = script.Parent.Minutes.Value
local seconds = 0

repeat

	if seconds <= 0 then
		seconds = 59
		minutes = minutes - 1
	else
		seconds = seconds - 1
	end

	if seconds <= 9  then
		timer.Text = "[ "..tostring(minutes)..":0"..tostring(seconds).." ]"
	else
		timer.Text = "[ "..tostring(minutes)..":"..tostring(seconds).." ]"
	end
	wait(1)
until minutes <= 0 and seconds <= 0

1 Like

Try using task.wait(1), it’s a more precise and efficient version of wait() basically.

Dont rely on timings from wait to be perfect, instead use a frame based system and the return from task.wait to better determine how much longer to wait

local timeRemaining = 5
while timeRemaining > 0 do
  timeRemaining -= task.wait()
  text = math.floor(timeRemaining)
end

And, you can format your minutes:seconds from a single second variable using the % operator

local timeRemaining = 96
local minutes = math.floor(timeRemaining / 60) % 60
local seconds = timeRemaining % 60

Don’t use wait man, use task.wait(). :sob:

Alternatively you can use this accumulator loop if this script is ran from the server. It also works smoothly when there’s server lag.

task.wait() based loops are still discouraged:
The While-Wait-Do Idiom, by cntkillme: Addressing while wait() loops - Resources / Community Resources - DevForum | Roblox

--!strict


local rate: number = 1 -- 1 times a second
local accumulated: number = 0

game:GetService("RunService").Heartbeat:Connect(function(deltaTime: number)
	accumulated += deltaTime
	while accumulated >= rate do
		accumulated -= rate
		-- Main logic goes here.
	end
end)

Sorry I am not really that much of a scripter. Is this right?

local timeRemaining = 240

local minutes = math.floor(timeRemaining / 60) % 60

local seconds = timeRemaining % 60

while timeRemaining > 0 do

timeRemaining -= task.wait(1)

if seconds < 9 then

script.Parent.Text = "[ "..tostring(minutes)..":0"..tostring(seconds).." ]"

else

script.Parent.Text = "[ "..tostring(minutes)..":"..tostring(seconds).." ]"

end

end

Oops I forgot to put the

local minutes = math.floor(timeRemaining / 60) % 60

local seconds = timeRemaining % 60

in the

if seconds < 9 then

thanks, it works great now. But I just realised it’s still kinda inaccurate…

Here you go, I hope this is to your liking. I performance checked your version of the script against lag and seems like it doesn’t do a good job at it.

--!strict


local textObject: any = script.Parent.textObject
local timeRemaining: number = 240
local rate: number = 1 -- 1 times a second
local accumulated: number = 0

game:GetService("RunService").Heartbeat:Connect(function(deltaTime: number)
	accumulated += deltaTime
	while accumulated >= rate do
		accumulated -= rate
		if timeRemaining > -1 then
			textObject.Value = string.format(
				'[%d:%d]',
				math.floor(timeRemaining * .0166666667),
				timeRemaining % 60
			)
		else
			print("TIME RAN OUT! Resetting timer...")
			timeRemaining = 240
		end
		timeRemaining -= 1
	end
end)

finished

2 Likes

can I put that in my text gui?
image

Yes, however make sure to change the path accordingly, so textObject variable becomes: script.Parent.Timer.TimeRemaining

And change:
game:GetService("RunService").Heartbeat to game:GetService("RunService").RenderStepped

Okay I’ll go try it out right away.

image
I got an error, I am guessing I need to change it back to

game:GetService("RunService").Heartbeat

I am not using a local script

Change the script to a LocalScript and try (notice icon):
image

edit: By changing I mean copy pasting the contents of the Script into a newly made LocalScript, then replace the Script with the LocalScript.

Oh wait, I forgot to change the “Value” to "Text
"

Nope, this is the local script I have in my text label. Also the text label is not in starter gui. Yeah I forgot to mention it’s in workspace in a part.

local textObject: any = script.Parent
local timeRemaining: number = script.Parent.TimeRemaining
local rate: number = 1 -- 1 times a second
local accumulated: number = 0

game:GetService("RunService").RenderStepped:Connect(function(deltaTime: number)
	accumulated += deltaTime
	while accumulated >= rate do
		accumulated -= rate
		if timeRemaining.Value > -1 then
			textObject.Text = string.format(
				'[%d:%d]',
				math.floor(timeRemaining * .0166666667),
				timeRemaining % 60
			)
		else
			print("TIME RAN OUT! Resetting timer...")
			timeRemaining = 240
		end
		timeRemaining -= 1
	end
end)

I assume then that you want to change the TextLabel inside a SurfaceGUI on a Part? Like this:

image

So that the countdown is shown where “Label” is?

finished2

Yeah I already found the solution, thanks for your help and have a nice day. Sorry for taking so long. Also one little question you could answer for me: How would I put a 0 before the seconds when they are less then 9?

1 Like

Sorry for replying again but I am just making sure you see the edit I did on the message above. I am so sorry.

You’re welcome, glad to help.

For that I’d turn the modulus calculation into a variable, since it’s going to get referenced twice, and same with formatString since it’s going to change when the seconds are below 10 (I assume below 10 is what you meant).

I also gave you a max time value, so it’s easier to manage for example when the value gets reset:

Here’s the full script:

--!strict


local textObject: any = your directory goes here
local MAX_TIME_DEFAULT: number = 240
local timeRemaining: number = MAX_TIME_DEFAULT
local rate: number = 1 -- 1 times a second
local accumulated: number = 0

game:GetService("RunService").Heartbeat:Connect(function(deltaTime: number)
	accumulated += deltaTime
	while accumulated >= rate do
		accumulated -= rate

		if timeRemaining > -1 then
			local seconds = timeRemaining % 60
			local formatString = '[%d:%d]'
			if seconds < 10 then
				formatString = '[%d:0%d]'
			end
			textObject.Text = string.format(
				formatString,
				math.floor(timeRemaining * .0166666667),
				seconds
			)
		else
			print("TIME RAN OUT! Resetting timer...")
			timeRemaining = MAX_TIME_DEFAULT
		end
		timeRemaining -= 1
	end
end)
1 Like

Thank you so much! This is all I needed. Sorry for interrupting you.

1 Like