Restart a for loop without breaking the while loop?

Hi, I’m making a wave based zombie game but I’m having an issue that I haven’t been able to solve. My for loop acts as a timer, if the timer hits zero the while loop restarts again but the problem is if the wave changes the timer needs to restart but I don’t know how to do that. Can anyone help. Here’s the script:

local Players = game:GetService("Players")
local RS = game:GetService("ReplicatedStorage")
local gv = RS.Values.gv
local DiedValue = RS.Values.DV
local wave = RS.Values.Wave
local ZombiesRemaining = RS.Values.ZombiesRemaning
local TimeToWait = RS.Values.TimeToWait.Value
local IGT = RS.Values.InGameTime
local Restart = false

local playersInRound = {}
local playersDisconnected = {}
local playerDies = {}
local lobbyTime = 20
local isOverrided = false
local inRound = false

Players.PlayerRemoving:Connect(function(Player)
	table.insert(playersDisconnected, Player)
	if table.find(playersInRound, Player) then
		table.remove(playersInRound, table.find(playersInRound, Player))
		if #playersInRound == 0 then
			print("Everyone has died!")
			inRound = false
		end
	end
end)

local function doRound()
	inRound = true
	playersInRound = {}
	playersDisconnected = {}
	
	for _, Player in ipairs(Players:GetPlayers()) do
		local Character = Player.Character
		local Humanoid = Character:WaitForChild("Humanoid")
		local HRP = Character:WaitForChild("HumanoidRootPart")
		HRP.CFrame = CFrame.new(0, 0, 0) --good spawn location
		table.insert(playersInRound, Player)
		Humanoid.Died:Connect(function()
			table.insert(playersDisconnected, Player.Name)
			table.remove(playersInRound, table.find(playersInRound, Player))
			if #playersInRound == 0 then
				print("Everyone has died!")
				inRound = false
				task.wait(3)
			end
		end)
	end
end

wave.Value = 1

function Loop()
	while true do
		Restart = false
		for i = lobbyTime, 0, -1 do
			gv.Value = i
			wait(1)
		end
		coroutine.wrap(function()
			for i = 120, 0, -1 do
				IGT.Value = i
				wait(1)
			end
		end)
		if ZombiesRemaining.Value <= 0 then
			wave.Value = wave.Value + 1
			ZombiesRemaining.Value = 10 + wave.Value
			if TimeToWait ~= 0.5 then -- If it hasn't reached 0.5 yet
				TimeToWait = TimeToWait - 0.1 -- Decrease the current TimeToWait by 0.1
			else
				TimeToWait = 0.5
			end
			if wave.Changed:Connect(function()
				DON'T KNOW WHAT TO DO HERE OR IF THIS IS THE RIGHT THING TO DO.
			end)
			end
			if IGT == 0 then
				Restart = true
				break
			end
		end
	end
end

if Restart == true then
	Loop()
end

task.spawn(function()
	while task.wait() do
		if not inRound then
			doRound()
		end
	end
end)

Instead of a while true do loop try using a while Restart loop and get rid of the

if Restart == true then
	Loop()
end

section.

If I do this the waves will start back from 1 and I want that to continue. I just want to know how to reset the timer when the wave.Value has changed.

Try to put in the if condition this:

task.spawn(Loop)
return

1 Like

I think you should rebuild the entire timer approach, I was reading your code and I think it has some issues, read the comments:

I removed everything and just focusing on the Loop function.

local lobbyTime = 20
local IGT
local gv

function Loop()
	warn("the while loop started")
	-- Constantly repeat this block by using while loop
	while true do
		warn("loop ran")
		Restart = false
		
		-- Counting to 20 yielding, when its over, the rest of code will run
		for i = lobbyTime, 0, -1 do
			print("lobby time:", i)
			gv = i
			wait(1)
		end
		
		-- First time the "lobby 20 seconds" are over
		-- wrap and run
		coroutine.wrap(function()
			warn("coroutine started")
			for i = 120, 0, -1 do
				IGT = i
				warn("seconds in coroutine:", i)
				wait(1)
			end
		end)() -- you were forgeting the run (), otherwise the coroutine never fires
		-- and its running independently from the iteration
		
		-- In first iteration, this doesnt fires, CONTINUE
		if IGT == 0 then
			Restart = true
			break
		end
		
		-- We reached here while coroutine still running, it will last 120 seconds independently from the iterations
		-- A new iteration is about to start
		-- And it will repeat whole code again
		-- Means, after the first 20 seconds "lobby loop" everything in this block will run again
		-- Starting a new for i = lobbyTime, 0, -1 do loop, while coroutine of 120secs still running
		-- Causing overlapping loops
	end
end

And how you could change reset/set the timer.
You did a coroutine.wrap which is never yielding or accepting a updated value, it will perform a loop until reaching 120 seconds, no way to stop it/change it, unless you referenced the amount of “time” to iterate outside the coroutine, a variable that holds a number of seconds in which the loop will react, so you can overwrite it from outside.

So how could I change the second timer, the reason for the coroutine is so if the wave changes it will still listen for that, but I have no idea how to restart the second timer when the wave changes without repeating the while loop. If I repeat the while loop the intermission will start again and the wave will revert back to wave one. Can I change the coroutine loop to something else?

if you only want to change the variable that the coroutine is using without yielding it to receive updated data, you could use an external variable, check this example (you can even run it in command bar)

-- "global" value of the timer
local value = 5

-- the coroutine
coroutine.wrap(function()
	while true do
		task.wait(1)
		value -= 1
		print("Timer:", value)
	end
end)() -- run

-- Change value after 10 seconds
task.wait(10)
value = 500

-- You can just change that "global" variable for the coroutine to any number you want
value = 100

Or you could yield the coroutine, or you could get rid of coroutine and use task.spawn, and constantly reading your timer based on events/stages in your round.
Idk depends what you prefer. I just suggest rebuilding your timer, specially if its very important for the game. Focus on it and give it more importance as a “leading system”

I have updated the code but how do I run the coroutine?

function Loop()
	while true do
		Restart = false
		for i = lobbyTime, 0, -1 do
			gv.Value = i
			wait(1)
		end
		
		local value = RS.Values.MainGame
		
		coroutine.wrap(function()
			while true do
				task.wait(1)
				value.Value -= 1
				IGT.Value = value.Value
				print("Timer:", value.Value)
			end
		end)
	
		if ZombiesRemaining.Value <= 0 then
			wave.Value = wave.Value + 1
			value.Value = 120
			ZombiesRemaining.Value = 10 + wave.Value
			if TimeToWait ~= 0.5 then -- If it hasn't reached 0.5 yet
				TimeToWait = TimeToWait - 0.1 -- Decrease the current TimeToWait by 0.1
			else
				TimeToWait = 0.5
			end

			if IGT == 0 then
				Restart = true
				break
			end
		end
	end
end

Add the parenthesis, but I see almost everything is the same

coroutine.wrap(function()
			while true do
				task.wait(1)
				value.Value -= 1
				IGT.Value = value.Value
				print("Timer:", value.Value)
			end
		end)() -- this last parenthesis

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.