Can I pause a coroutine from outside of it?

  1. What do you want to achieve?
    I want to know if it is possible to stop a coroutine from outside of it. I know coroutine.yield exists, but that only works if it is inside of a coroutine. This is what I want to do: create the coroutine, start it, then stop it at another time.

Here is an example of what I want:

local coro = coroutine.create(function()
    while wait(1) do
        --code
    end
end)

wait(5)

coro:Stop() -- Stop() doesn't exist, but its what I'm trying to do

Looking at the coroutine documentation (coroutine | Documentation - Roblox Creator Hub and coroutine | Documentation - Roblox Creator Hub), it doesn’t look like it possible, but I could be missing something.

If that is not possible using coroutines, is there an alternative to coroutines that I can use? I’m using it for an enemy system, where the enemies are spawned and shoot bullets indefinitely and are stopped when the player dies or goes to the next level.

1 Like

Why don’t you just use the heart beat event of the RunService, your current solution could work by just adding a proper condition to the while loop, but I would use the RunService.

local RunService = game:GetService("RunService")

local Connection = nil

Connection = RunService.Heartbeat:Connect(function()
 
end)

--then  to stop it, you would do:

Connection:Disconnect()

I would, but each enemy shoots at a different amount of time and some enemies can be spawned after others. Also, my example I gave is much less complicated than I have it in-game, I just simplified it for the question.

Imo, in future, it’s better to use the actual Lua documentation i.e. for coroutines look here. You can pause them by calling coroutine.yield()

For your use case though, I think you probably want something like this module I’ve just put together for you:

Module (of which I’ve called ‘threads’):

local threads = { }

function threads.new(foo)
	local this = { }
	this.active = false
	this.func   = foo
	
	-- private
	local function Fire(f)
		local event = Instance.new 'BindableEvent'
		event.Event:connect(function ()
			f(this)
		end)
		event:Fire()
	end
	
	-- public
	function this:setFunction(foo)
		this.func = foo
		return this
	end
	
	function this:play(t)
		this.active = true
		if this.func then
			Fire(this.func)
			if t and type(t) == 'number' then
				delay(t, function ()
					this.active = false
				end)
			end
		end
		return this
	end
	
	function this:stop()
		this.active = false
		return this
	end
	
	return this
end

return threads

Example usage:

--> Let's call our module into memory
local threads = require(script.threads)

--> Start a new thread 
--[!] You can pass a function to this threads.new method to auto set the function instead of calling 'setFunction'
--[!] Note when you test this that your output will print both the threads simultaneously e.g. 'Hello, world!' and 'World, hello!' simultaenously:
local newThread = threads.new()
newThread:setFunction(function (thread) --> Set the function for the new thread
	--> Must always have thread.active if you're wanting it to loop based on the thread activity set by ':play()' and ':stop()'
	while thread.active do
		print 'Hello, world!'
		wait(1)
	end
end)

--> Play our thread for 5 seconds
newThread:play(5) --> If you don't pass a number, it will run indefinitely until you call 'newThread:stop()'

--> Let's demonstrate some chaining...
--[!] 'threads.new():setFunction(someFunction):play(someNumber)' is a perfectly valid call as shown below:
local otherThread = threads.new()
otherThread:setFunction(function (thread)
	--> Let's loop until we're no longer active...
	while thread.active do
		print 'World, hello!'
		wait(1)
	end
	--> After a 1 second delay, let's play our own thread again...
	delay(1, function ()
		--> Let's change our function:
		thread:setFunction(function (thread)
			while thread.active do
				print 'Many worlds'
				wait(1)
			end
		end)
		--> Now let's play it all over again!
		thread:play()
	end)
end):play() --> as I said, no numbers means it'll play indefinitely until something calls the ':stop()' method

--> Let's stop our otherThread after 5 seconds
delay(5, function ()
	otherThread:stop()
end)
8 Likes

I did end up fixing it already, but thanks for the effort! That’s a long script for just one post.

1 Like

Externally suspend the execution of a coroutine?

local active = true
local thread = coroutine.create(function()
	local o, i = os.clock(), 0   

      while true do 
          --//code, builtin loop
	      wait(1) -- reliability depends on the amount of time you yield for
		  i += 1	
		  print(i)       
		  if not active then coroutine.yield() end	 
	  end
 end)
coroutine.resume(thread) -- initiate

wait(3) -- stops counting after about 3 seconds
active = false
--[[
	wait(3) 
	-- "revive" it like this
	active = true -- set the boolean to true
	coroutine.resume(thread) -- execute
]]
12 Likes