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
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.
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)
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
]]