While loop breaks after calling function

When calling a function, the loop here breaks, only running once.

while wait(1) do
    print("Run")
	local players = 0
	for i, v in pairs(Players:GetChildren()) do
		players += 1
	end
	if players >= 1 then
		if CanWeStart and not IsTheRoundGoing then
			PickTeams()
			CanWeStart = false
			IsTheRoundGoing = true
		end
	end
end

I’d imagine this is where coroutines would come in, but so far my attempts at using them in this situation had failed.

I do not know why its breaking but we can try and optimize the code a little bit and see if it helps. Instead of running that for loop, you can just do

while wait(1) do
        print("Run")
	local players = game.Players:GetChildren()
	
	if #players >= then
		if CanWeStart and not IsTheRoundGoing then
			PickTeams()
			CanWeStart = false
			IsTheRoundGoing = true
		end
	end
end

Side thought, the calling PickTeams() could be breaking your loop but obviously I cannot know for sure. Try running this edited code and see if it still has the issue first.

1 Like

The loop works fine when PickTeams() is removed. Your suggestion may have optimized the code, but the loop still breaks when the function is called.

So PickTeams() is breaking the loop, is that what you’re saying? If so and you need help figuring it out go ahead and post the code and we’ll tackle it together.

I’m not exactly sure now. After testing this code below, the loop works fine, printing “Run” every 1 second.

local function callFunction()
	print("func")
end

while wait(1) do
	print("Run")
	local players = game.Players:GetChildren()
	if #players >= 1 then
		if CanWeStart and not IsTheRoundGoing then
			callFunction()
			CanWeStart = false
			IsTheRoundGoing = true
		end
	end
end

As for the original code, it’s pretty long so I’ll post what I’d feel is relevant.


local function RoundEnd()
	IsTheRoundGoing = false
	CanWeStart = true
	RoundEndRM:FireAllClients() -- Kills remaining players
end

local function StartRound(RanPlayer)
	IsTheRoundGoing = true
	
	for i, v in pairs(Players:GetChildren()) do
		if v.Team == EnemyTeam then
			v.Character.HumanoidRootPart.CFrame = CFrame.new(EnemySpawn.Position)
		else
			v.Team = InnoTeam
			v.Character.HumanoidRootPart.CFrame = CFrame.new(InnoSpawn.Position)
		end
	end	
	RoundStartedRM:FireAllClients()								-- Round started
	for Time = 100, 0, -1 do 
		RoundTimerRM:FireAllClients(Time)						-- Counts down how long round is left
		if Time == 0 then
			RoundEnd()
		end
		wait(1)
	end
end

local function PickTeams()								-- Chooses teams
	for Time = 20, 0, -1 do 
		CountDownUntilRoundRM:FireAllClients(Time)				-- Timer
		wait(1)
	end
	local AllPlayers = Players:GetChildren()
	
	local RanPlayer = AllPlayers[math.random(1, #AllPlayers)]	-- Randomly picks someone for enemy
	RanPlayer.Team = EnemyTeam
	
	TeamNotifierEvent:FireAllClients()
	wait(3)
	StartRound(RanPlayer)
end

while wait(1) do
	print("Run")
	local players = game.Players:GetChildren()
	if #players >= 1 then
		if CanWeStart and not IsTheRoundGoing then
			PickTeams()
			CanWeStart = false
			IsTheRoundGoing = true
		end
	end
end

If I’m not mistaken, I believe it’s the for loop in the PickTeams() function which is stopping the while loop.

The script will go and execute the function, but will stop to execute the for loop in the function, which will take 20 seconds to continue. Try adding prints in some places and see if that works.

Adding prints where? The code works fine, the problem is the while loop only runs once, thus the code only runs once, and doesnt work when the round is over and a new round is supposed to begin.

Just below when you define the PickTeams() function…

	for Time = 20, 0, -1 do 
		CountDownUntilRoundRM:FireAllClients(Time)				-- Timer
		wait(1)
	end

Add a print after that statement saying print("Continuing"), to incicate the rest of the function is running.

Test your game and have the while loop run. Wait 20 seconds. After you wait the 20 seconds, do you see Continuing in the output?

Idk what is happening, maybe you can go in debug mode. In debugmode, you can see every single step of your code. This is very usefull. And I should say: „Don‘t use a while wait() do loop“.

The DebugMode:

It is hard at first, but is very, very usefull with this sorrt of bugs.

Why would it not stop? I tested it out anyway, and yes the loop stops after 20 seconds.

	for Time = 20, 0, -1 do  
    -- 20 = start, 0 = end, -1 = deincrementor, therefore loop stops when 0 is reached

@Eternalove_fan32 Debugger is enabled by default, and what would you suggest to replace the while loop?

1 Like

Remove these from after PickTeams(). They are preventing your rounds from restarting, since your conditional checks for the opposite of both variables before starting the round.

while wait(1) do
    print("Run")
	local players = 0
	for i, v in pairs(Players:GetChildren()) do
		players += 1
	end
	if players >= 1 then
		if CanWeStart and not IsTheRoundGoing then
			PickTeams()
		end
	end
end

If you haven’t noticed.

local function RoundEnd()
	IsTheRoundGoing = false
	CanWeStart = true
	RoundEndRM:FireAllClients()
end

I’m strongly suspecting I would need to have the loop run independently but my solutions so far using coroutines had failed.

The variables are reassigned from the RoundEnd() call after the PickTeams() line because everything is all on the same thread.

Every line of code from PickTeams() to StartRound() to RoundEnd() executes, then CanWeStart = false and IsTheRoundGoing = true executes.

It seems like the intention would be to have these assignments as the round is beginning, so you should either move them just before PickTeams() or move them into that function, but the current assignments are overwriting RoundEnd()'s assignments.

Moving the variables before PickTeams() still doesn’t change the fact that the loop only runs once. Even testing the code without the two booleans, the round will not start again after the player dies.

Have you tried it with the change? Does the game ever restart once started, or just not when a player dies? I’m able to run it on my end with the change.

Solved it. I had decided to use BindableEvent to run the loop independently.

local bindableEvent = Instance.new("BindableEvent")
bindableEvent.Event:Connect(function()
	local players = game.Players:GetChildren()
	if #players >= 2 then
		if CanWeStart and not IsTheRoundGoing then
			CanWeStart = false
			IsTheRoundGoing = true			
			PickTeams()
		end
	end
end)
while wait(1) do
	bindableEvent:Fire()
end	
1 Like