How do you create a timer that counts a players time?

Yes that is another option as well.

The point is, doing wait() manually worse than using tick(), os.time(), or another similar method that’s meant to be used for that, as well as accurately counts the time - free of lag or most problems you could encounter with wait().

1 Like

Also, it’s not actually waiting for 0.01 seconds to let you know. The fastest you can do with wait() is 0.03, no lower. So it’s not working correctly. I recommend you switch it to an os.time or tick() method instead.

1 Like

As I stated, it runs perfectly fine on a 0.01 time. I’m not trying to fight.

So, if I were to add to add an if statement to the script it doesn’t work. I stated if player.Started.Value == true then the timer would start but it didn’t.

No it does not. You’re not aware that it’s only running at 0.03 seconds, not 0.01? The limitation of wait() is 0.03, which is about 1/30th of a second.

Take a look for yourself: Decrease the minimum time in wait() to 1/60th of a second

And sorry, I don’t want to be rude at all. I just want to help out to make the solution work.

2 Likes

well, I havent really done time based scripts so I am not used to using tick() or os.time much. So I wouldn’t be able to make it different anyways.

here is a script that will run in the way you wanted it to. It will only give the time if they have started.

local milisecond = 0
local second = 0
local minute = 0
local hour = 0
while wait(0.01) do
	if milisecond >= 60 then
		milisecond -= 60
		second += 1
	end
	if second >= 60 then
		second -= 60
		minute += 1
	end
	if minute >= 60 then
		minute -= 60
		hour += 1
	end
	if game.Players.LocalPlayer.Started.Value == true then
		milisecond += 1
	end
	script.Parent.Text = hour..":"..minute..":"..second.."."..milisecond
end
1 Like

So even though you are defining wait(0.01) its not gonna work at all because the wait() can only go to 0.03 so your script is not gonna work as intended because its gonna run .02 seconds slower than it is meant to. The script may still work because Lua is a forgiving language but your time will always be off. I believe if you change wait to tick() it should fix that problem because the tick() function allows you to start from 0.01.

1 Like

Sorry! Another question. How would I stop the timer and reset it if a player dies or touches the end part?

it already automatically resets if they die. now if you wanted to reset it, just destroy the gui and replace it.

So to stop it i have to destroy it? Then how would I replace it?

First of all, you’ll want to count the seconds somehow (duh).
I’d recommend marking a start time with os.clock()

Next you’ll want to figure out how to transform this into your timer. The easiest way to do this is using some modulos and some flooring. I like to define all of my time amounts in variables.

Lastly, you’ll want to make sure each piece of the timer except the first is two digits (which is also pretty easy).

You can update the timer at any time, even randomly if you wanted to, and it’ll accurately measure time.

Here’s a full implementation of this (I really recommend trying to understand it, its better to understand the code than to just use it and not have learned anything!):

local RunService = game:GetService("RunService")

local SECOND = 1
local MINUTE = SECOND * 60
local HOUR = MINUTE * 60

local startTime

local function getTime()
	return os.clock()
end

local function readableTime(timer)
	-- First of all, get all of the times in their amounts
	local remainder = timer -- Basically this is the "not included" time
	local hours = math.floor(remainder / HOUR) -- Figure out the number of whole hours
	remainder = timer % HOUR -- Update our remainder time
	local minutes = math.floor(remainder / MINUTE) -- Figure out the number of whole minutes in the remaining time
	remainder = remainder % MINUTE -- Update our remainder time again
	local seconds = math.floor(remainder / SECOND) -- Figure out the number of whole seconds in the remaining time
	remainder = timer % SECOND
	local hundredthsOfASecond = math.floor(remainder * 10^2) / 10^2 -- Take the first two decimal digits
	
	minutes = tostring(minutes)
	if #minutes < 2 then -- Make sure the minutes section is two digits, if not, its less than 10, so we can add a 0
		minutes = "0"..minutes
	end
	
	seconds = tostring(seconds)
	if #seconds < 2 then -- Make sure the seconds section is two digits, if not, its less than 10, so we can add a 0
		seconds = "0"..seconds
	end
	
	hundredthsOfASecond = tostring(hundredthsOfASecond):sub(2) -- Convert the decimal results to a string and remove the first 0
	
	return table.concat({hours, minutes, seconds..hundredthsOfASecond}, ":") -- Concatenate everything with a : in between
end

local function updateTimer()
	local currentTime = getTime()
	local timer = currentTime - startTime
	local timerText = readableTime(timer)
	
	-- Set the timer text
end

local function startTimer() -- Start the timer!
	local currentTime = getTime()
	if startTime ~= currentTime then
		startTime = currentTime
		
		coroutine.wrap(function() -- Create a new thread for the timer to run in
			local timerTime = startTime
			while timerTime == startTime do -- Make sure the current timer is running
				updateTimer()
				RunService.Heartbeat:Wait() -- Wait for Heartbeat (Approximately 1/60th of a second)
			end
		end)()
	end
end

local function stopTimer() -- Stop the timer
	startTime = 0 -- This causes other timer loops to exit since the timer will check if it has been changed and exit if it has
end

startTimer()
-- Other code
4 Likes

So you recommend me using a module?

Well, I mean, its up to you how you do it. I’ve simply provided an explanation for how you can accurately track the time that has passed and create a readable time from that (e.g. 1:02:03.28).

You can implement it in its own module, and maybe even make a Timer object so you can use more than one timer at once, or you can use it in its own unique script.

Hmm is it ok to implement this sort of code into a local script? Because I want it to time the player when doing the obby with a gui.

Mhm! It honestly makes sense to me to only include the timer code in local scripts since updating a property like that would replicate each time. If ever you needed to synchronize other player’s timers, you could just send the start time to the client.

You would need to translate the server’s time into the client’s time though, which you could do in a few ways, the easiest of which is just to have the server send the os.clock() result to the client once, and the client can compare its own os.clock() value:

local serverClockTime = getServerClockTimeSomehow()
local clientClockTime = os.clock()
local clockTimeOffset = serverClockTime - clientClockTime

function getTime()
	return clockTimeOffset + os.clock()
end

That’s certainly not perfect but the most you’ll end up with is players seeing a slightly delayed timer. You could resynchronize the clocks occasionally if you wanted to, and you can get even more complicated and average a couple of the previous values together when you do that, but, that’s really only if you care.

Another option if you want complete accuracy in a much easier way is to use os.time() rather than os.clock() since it should be synchronized between the client and the server, whereas os.clock() is not synchronized (its the newly added version of tick essentially). The downside to this is you lose out on decimal seconds, but, if you don’t care about this, you don’t care about it.

2 Likes

Hello! So I created a new script, with tick. This is the script, but I don’t know how to make a condition before running the script and how to stop the timer and reset it. Any suggestions? Here is the script…

local start = tick() 

while true do
	wait()
		
	local diff = tick() - start
	
	local min = math.floor(diff / 60)
	local sec = diff - min*60
	local mil = math.floor((sec - math.floor(sec)) * 10)
	sec = math.floor(sec)
		
	script.Parent.Text = min..":"..sec..":"..mil
end

Well, you can use a function to start the timer. To stop the timer you can just have some condition in the loop, and, you can have a function which causes the timer to stop by changing something. The way I did it in my example script above is by basically seeing if start was still the same, so, if you started a new timer, it’d exit the loop since the start time was different, that way multiple timers wouldn’t run at once. And then to make the timer exit, I just change the start time to 0.

And as you can see in my example code, the way I made the timer run without blocking other code is by putting it in a new thread.

I’d also recommend using os.clock now instead of tick (os.clock is a new function which does almost the same thing, but, when it was implemented Roblox suggested no longer using tick, I’d assume either for performance reasons, or something else)

So, should I just replace the tick statements with os.clock?

Mhm, although, its not really required to, if you want to stick with “best practices” like that you can. I personally prefer to just because I end up making a lot of high scale projects.