Scripting HelpersARCHIVE
A little piece of Roblox history. Preserved for everyone, one question at a time.Read about the archive →
COMMUNITY QUESTION

Coroutine not resuming the second time?

Introduction I have a round-base game which depends on a timer for each round. I want the client to be able to see how long until the round is over, thus I created an IntValue in ReplicatedStorage which has the os.time() constant as to when the game is meant to end.

The server side looks like this, where game_end is the IntValue

function set_timer(t)
	if game_end then
		local future_time = (t~=0 and (os.time() + tonumber(t))) or 0
		game_end.Value = future_time
	else
		warn("GameEnd timer IntValue not found inside ReplicatedStorage -> GameController/SetTimer")
	end
end

Then, on the Client, inside of a StarterGui, I have this code:

local GameEnd = game.ReplicatedStorage:WaitForChild("GameEnd")
local Clock = script.Parent.Clock
local ClockRunner

ClockRunner = coroutine.create(
	function()
		while wait(1) do
			local secondsLeft = os.difftime(GameEnd.Value, os.time())
			local function SecondsToStamp(Seconds)
				if Seconds<=0 then return "0:00" end
				return string.format("%d:%.2d", Seconds / 60, Seconds % 60)
			end

			local format = SecondsToStamp(secondsLeft)
			Clock.Text = (" Time Left: "..format)
			if format == "0:00" then if coroutine.isyieldable(ClockRunner) then coroutine.yield(ClockRunner) end break end
		end
	end
)

GameEnd:GetPropertyChangedSignal("Value"):Connect(function()
	if os.difftime(GameEnd.Value-os.time()) > 0 then
		coroutine.resume(ClockRunner)
	end
end)

The first time the value is changed, the timer works and we get this effect. However, the second time it runs, the coroutine isn't resumed and the timer does not work.

How can I properly do this?

How can I resume this coroutine, seeing that it's not doing so?

7 comments

0

I'm not 100% inclined when it comes to coroutines so I will not submit a formal answer. However, have you tried to wrap() the coroutine and call it like a function when it needs to be resumed? Wrap is the same as create, except wrap returns a function that resumes the coroutine each time it is called

0

local newcour = coroutine.wrap(function() print("Wrap") end) newcour()

0

yes but what if I need to yield it @WizyTheNinja?

0

I tried it, didn't work :/

0

Well it looks like you are just yielding when the timer is over, and starting back up when the timer resets. Running Wrap() will run the function until the code is done, on a seperate thread. It's really no different than running just a straight function, other than the fact that the rest of your script will still run even if the coroutine is. If I am right on my guess, you just need to call

0

the wrap() function everytime the timer resets, instead of yielding it until it does.

0

Hmm. Let me debug around with it and see if I can get a working code going. 

1 answer

I played around with it and got this to work. Everytime the value changes and is greater than 0 it will initiate the coroutine countdown. Inside the script I added a loop that initiated a 5 second countdown multiple times while waiting 6 seconds inbetween each loop, and the timer reset and counted down fine. I'm not sure why you were trying to yield other than waiting for a new timer, but this one uses a for loop instead of a while loop. When the timer changes, it detects how long it is and runs a for loop for that long. Once all the code in a coroutine is finished, so is the coroutine. So having a while loop inside of it and using wrap() will cause it to continue running until the while loop breaks, so using a for loop is the optimal way here.

GameEnd:GetPropertyChangedSignal("Value"):Connect(function()
	if os.difftime(GameEnd.Value-os.time()) > 0 then
		print("Changed")
		local timer = os.difftime(GameEnd.Value, os.time())
		print(timer)
		local starttimer = coroutine.wrap(function()
			for i = 1, timer do
				wait(1)
				print("Running")
				local secondsLeft = os.difftime(GameEnd.Value, os.time())
				local function SecondsToStamp(Seconds)
				if Seconds<=0 then return "0:00" end
					return string.format("%d:%.2d", Seconds / 60, Seconds % 60)
				end
				local format = SecondsToStamp(secondsLeft)
				Clock.Text = (" Time Left: "..format)
			end
		end)
		starttimer()
	end
end)

This discussion is preserved as it was. New answers, comments, and votes are closed.