Can I stop a coroutine while it is in a loop with a yield?

Hello!

I was wondering if it was possible to stop a coroutine (in my case, a timer) that has a yield, or is there any way to stop a loop that has a yield?

For example, if a timer is going on and a player leaves, is there a way to stop that loop (and ultimately stop the round)?

For example,

local myLoop = coroutine.wrap(function()
    for i = 1, 60 do
        wait(1)
    end
end)

myLoop()
game.Players.PlayerRemoving:Connect(function()
    myLoop.stop() -- where the loop would stop
end
3 Likes

You could create a boolean to say whether or not there is enough players and check if that bool is true within the loop. If it isnt true, break the loop. Something like this maybe? Sure there are other ways, and you can implement your logic within it but breaking the loop under a certain circumstance should do the job :slight_smile:

edit: Completely forgot it was a coroutine, this will stop the loop within the coroutine my bad!

local myLoop = coroutine.wrap(function()
	local enoughPlayers = true
	for i = 1, 60 do
		wait(1)
		if not enoughPlayers then break end
		
		game.Players.PlayerRemoving:Connect(function()
			enoughPlayers = false
		end)
	end
end)
myLoop()
3 Likes

I was actually curious about this in the past and this post reminded me about it. After some searching, perhaps yielding a coroutine could solve this problem? Here is the official Lua documentation:
https://www.lua.org/pil/9.1.html

Please test this and let me know if it works, as I am also curious.

3 Likes

I believe the issue with this is that it will wait until the wait() is over until termination, and the poster wants to terminate while the wait() is still ongoing.

2 Likes

The problem is that I don’t see it as a better alternative (in my case) than setting a variable with having enough players and the player that left (as @SkoobiDoobiDoo said). I’m just looking to see which player left to make a notification and send to the users, then end the round, breaking the loop.

I could just check every 0.1 seconds to see if there’s enough players and then set the second loop into a for loop with 10 iterations and a 0.1 second yield.

You can put the yield inside of the playerRemoving event, and that should end the coroutine immediately when a player leaves. With a boolean, you have to wait until the wait() is finished. For example, if you have:

for i = 1, 10 do
    wait(100)
    if boolean == false then
        break
    else
        print(i)
    end
end

This is an exaggeration but I am using it to show what I mean. It will wait 100 seconds before checking the boolean to terminate the function. However, it seems that you can immediately terminate the function by using coroutine.yield(coroutine). You can use the coroutine.yield() inside of the playerRemoving event, to immediately yield the coroutine even if it is during its wait(100). Meanwhile the other method will have to wait until the wait is finished to check the boolean.

1 Like

I’ll try that in a minute and let you know.

1 Like

I might also add that you won’t want to put the function that you access on termination within the coroutine. So if you have a function endGame() that is supposed to end the minigame, you wouldn’t want to put that within the coroutine you yield. That would yield as well and never end the game.

1 Like

I’m a bit confused, sorry.

local myLoop = coroutine.wrap(function()

    for i = 1, 100 do
        wait(100)

        game.Players.PlayerRemoving:Connect(function(plr)
            coroutine.yield() -- doesn't seem to yield until that wait is over.
            print(plr)
        end)
    end
end)

myLoop()
2 Likes

I realized I worded that a bit confusing. I’ll make a quick example and hopefully that will help.

1 Like

I apologize for the delay. This isn’t the behavior I was expecting it to have, trying to find an alternate solution.

1 Like

I haven’t yet found a way to terminate the loop and circumvent the wait(). There is likely a better way to achieve what you want without needing to do this.

Is there any reason you couldn’t connect the PlayerRemoving to a remote event which sends the notification?

Players.PlayerRemoving:connect(function()
     notification:FireAllClients()
     loopBoolean = false
end)

Therefore it would send the notification and then terminate the loop when it gets the chance. I believe I may have been overcomplicating from the beginning and not understanding your question. @SkoobiDoobiDoo’s response would suffice if you do not need the countdown to terminate immediately, but you could still send the remote immediately.

2 Likes