I’m trying to make a timer for multiple people, using coroutines. Not sure what else to add.
Here’s my script:
local RS = game:GetService('ReplicatedStorage')
local event = RS.Remotes.SendTimerData
for i,v in pairs(workspace.Teleporters.TowerTeleporters:GetChildren()) do
v.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild('Humanoid') then
local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
local timerCoroutine = coroutine.create(function()
local zero = 0
while true do
for i = 0, math.huge do -- mins
for i2 = 0, 59 do -- secs
for i3 = 0, 9 do -- 1/10 secs
local min, sec, ms
if i <= 9 then
min = zero..i
else
min = i
end
if i2 <= 9 then
sec = zero..i
else
sec = i
end
if i3 <= 9 then
ms = zero..i
else
ms = i
end
local timeToSend = min..':'..sec'.'..ms
print(timeToSend)
event:FireClient(plr, timeToSend)
wait(0.1)
end
end
end
end
end)
coroutine.resume(timerCoroutine)
end
end)
end
Hello, below I’ve created a basic example of a coroutine:
function testFunction(TestParam) --Function for Coroutine to run
while true do
print(TestParam)
wait(1)
end
end
for i = 1, 10, 1 do
--Creating the Coroutine
local timerCoroutine = coroutine.create(function()
testFunction(i) --Calls the function the Coroutine should run
end)
coroutine.resume(timerCoroutine) --Starting the Coroutine
end
This is how I would structure them when writing the code. I could be wrong but you may want to check your code logic as if you start a new coroutine each time someone touches the part, what happens if the same person touches the same part twice.
As I said above, I may be reading this incorrectly however I think it would start two coroutines for the same person which would be firing multiple events to the client with different timers?
Yeah, I plan on adding a debounce, however I wanted to create a single coroutine which would be stopped whenever they press the end part. I’m pretty new to coroutines so I’m not sure where to go from here. Wouldn’t your example create 10 coroutines though?
I’ll try to reformat my script closer to yours and let you know.
Eh, yeah you’re correct , for your case you would remove the for loop.
My personal choice is to put the functionality in a separate function just to separate the code a little bit.
Yeah a denounce should work fine for this I think.
You’re definitely along the right lines, just keep in mind that once the coroutine is started, if it has a while true do in it then it will run continuously.
I’m not sure if it’s the coroutine.create or resume that’s doing it, however it isn’t working. I updated it to be a bit closer to yours, I’ll put it below.
I also added a print in the .Touched function and it is being printed.
local RS = game:GetService('ReplicatedStorage')
local event = RS.Remotes.SendTimerData
local function calculateTime(plr)
local zero = 0
while true do
for i = 0, math.huge do -- mins
for i2 = 0, 59 do -- secs
for i3 = 0, 9 do -- 1/10 secs
local min, sec, ms
if i <= 9 then
min = zero..i
else
min = i
end
if i2 <= 9 then
sec = zero..i
else
sec = i
end
if i3 <= 9 then
ms = zero..i
else
ms = i
end
local timeToSend = min..':'..sec'.'..ms
print(timeToSend)
event:FireClient(plr, timeToSend)
wait(0.1)
end
end
end
end
end
for i,v in pairs(workspace.Teleporters.TowerTeleporters:GetChildren()) do
v.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild('Humanoid') then
local plr = game.Players:GetPlayerFromCharacter(hit.Parent)
local timerCoroutine = coroutine.create(function()
calculateTime(plr)
end)
coroutine.resume(timerCoroutine)
end
end)
end
Yeah, I added a print and it does seem to be starting. Must be an error with my script, but I am not sure what’s wrong with it as it seems to work outside of a coroutine.
I think the easiest way to test this is to put prints every 3 lines and see where it gets stuck. Also put a print on the receiver for the FireClient Call and see if the client is receiving it.
local function calculateTime(plr)
print('cor started')
local zero = 0
while true do
print('a')
for i = 0, math.huge do -- mins
print('b')
for i2 = 0, 59 do -- secs
print('c')
for i3 = 0, 9 do -- 1/10 secs
print('d')
local min, sec, ms
if i <= 9 then
min = zero..i
else
min = i
end
print('e')
if i2 <= 9 then
sec = zero..i
else
sec = i
end
print('f')
if i3 <= 9 then
ms = zero..i
else
ms = i
end
print('g') -- stops here, g is being printed
local timeToSend = min..':'..sec'.'..ms
print(timeToSend)
print('h')
event:FireClient(plr, timeToSend)
wait(0.1)
end
end
end
end
end
resume returns a boolean along with the result of the coroutine or an error message. I suspect there’s an error in the body of your callback function and resume is suppressing it. If you want errors to be thrown, you should use wrap instead.
local resumeCallback = coroutine.wrap(function ()
...
end)
local result = resumeCallback()
otherwise, you can do:
local thread = coroutine.create(function ()
...
end)
local success, result = coroutine.resume(thread)
if not success then
warn("Callback error:", result)
end
Fun-fact. You can actually pass arguments directly to a coroutine.
local function myCallback(a, b, c)
print(a, b, c)
end
local resume = coroutine.wrap(myCallback)
local result = resume(1, 2, 3)
-- or
local thread = coroutine.create(myCallback)
local success, result = coroutine.resume(thread, 1, 2, 3)