How to stop a function (from an event)

I have a function that will run like this:

local function attack()
    --load bow
    wait(3)
    --pull back
    wait(2)
    --release arrow
    wair(2)
    return
end

The real function is bigger than that, but as you can see there are many actions involved.

I want to stop this function as soon as I detect an event

local function attack()
    event.Event:Connect(function()
        return --but this only returns this function, it doesn't stop the functino "attack"
    end)
    --load bow
    wait(3)
    --pull back
    wait(2)
    --release arrow
    wait(2)
    return
end

How can I stop the function “attack” upon the event signal?

local stopAttack = false

local function onEvent()
    stopAttack = true
end

local function attack()
    event.Event:Connect(onEvent)
    
    -- Check before each action if stopAttack is true
    if stopAttack then return end
    --load bow
    wait(3)
    
    if stopAttack then return end
    --pull back
    wait(2)
    
    if stopAttack then return end
    --release arrow
    wait(2)
    
    return
end
local thread = task.spawn(attack)

event.Event:Connect(function()
task.cancel(thread)
end)

Idk, try this.

That is the method I have been using, but it is so messy and repetitive. Is there a cleaner way of doing so?

local function attack()
    local attackCoroutine = coroutine.create(function()
        --load bow
        wait(3)
        --pull back
        wait(2)
        --release arrow
        wait(2)
    end)
    
    local function onEvent()
        if coroutine.status(attackCoroutine) == "suspended" then
            coroutine.resume(attackCoroutine) 
        end
        coroutine.close(attackCoroutine)
    end
    
    event.Event:Connect(onEvent)
    
    coroutine.resume(attackCoroutine)
end

1 Like

I have a question

What is this if statement for?

1 Like

resuming twice might restart the thread or make a new one entirely, I’m not sure

1 Like

If it make it easier to understand, task.spawn() && task.cancel() basically does the same thing as the coroutine, without having to write all that.

But after opening it, and then calling coroutine.close() will error, beceause you can’t close a running coroutine :frowning: I get the error that I can’t close a running coroutine. How can I fix this?

pausing the coroutine so that it isnt running

I think Hexo’s reply is the best to use. Its simple and very easy to use, you should try it.

I will give it a try tomorrow!

Turns out that I can’t cancel a running thread :confused: is there another way?

try

local thread

thread = task.spawn(function()
   attack()
end)

event.Event:Connect(function()
  if thread ~= nil then
    task.cancel(thread)
  end
end)

This works well. However, there is a case when I need to exit the thread when something happens within that function like this:

local thread

function exit()
	task.cancel(thread)--errors "cannot cancel thread"
end

thread = task.spawn(function()
	playAnimation(animation) --animation last 1 second
	task.wait(animation.Length)
	if humanoid.Health <= 0  then --if player died before animation finished
		exit()
	end
end)


You can just use return there:

local thread

thread = task.spawn(function()
	playAnimation(animation) --animation last 1 second
	task.wait(animation.Length)
	if humanoid.Health <= 0  then --if player died before animation finished
		return -- return stops the thread from continuing
	end
end)

I have many things to do in the “return” function, and we should avoid repetitive code, that’s why I want to use a function.

local function exit(success)

	changedCon:Disconnect()
	self.troop:SetAttribute(reference.Attributes.DEBOUNCE,false)
	if success then
		self.troop:SetAttribute(reference.Attributes.TROOP_ACTION,"Refresh")
		self.hum.WalkSpeed = self.troop:GetAttribute(reference.Attributes.NORMAL_WALKSPEED)
	end

	if thread then
		task.cancel(thread)
	end
end
local thread

thread = task.spawn(function()
	playAnimation(animation) --animation last 1 second
	task.wait(animation.Length)
	if humanoid.Health <= 0  then
       exit() -- call your function here
	   return
	end
end)

Couldn’t you just call the function before the return?

Guess what, that is exactly what I used to be doing. However I feel like there should be a change to make the code cleaner :eyes::eyes:

Edit: because there will be events that can trigger an exit, so if i do

playAnimation(animation) --animation last 1 second
task.wait(animation.Length)
torso.Touched:Connect(function()
    exit()
    return
end)
if humanoid.Health <= 0  then
      exit() -- call your function here
	  return
end

the first “return” will not work for the outer function because it’s inside the touched function