How do I return a function when a value changes?

Imagine it like this: You have a function that has a lot of things happening and you don’t want to go through every line and put if not variable then return end… What would you do then? I would repeat until it changes to false but it wouldn’t continue the current thread. Please help!

I have a vague idea of what you’re trying to say, but could you explain it a bit more clearly? I can’t do anything with what you said here. Maybe provide some example code as well.

What I am trying to do is to end an function, when a variable changes to a specific value.

script.Parent.Generator.Lever.Lever.Attachment.ProximityPrompt.Triggered:Connect(function()
	script.Parent.Generator.Lever.Lever["Lever sound"]:Play()
	script.Parent.Generator.Lever.Lever.Start:Play()
	_G.TweenInstance(script.Parent.Generator.Lever.Lever.Engine,TweenInfo.new(10),{PlaybackSpeed = 1})
	_G.TweenInstance(script.Parent.Generator.Lever.Lever,TweenInfo.new(1.2),{Position = script.Parent.Generator.Lever.LeverToGoOpen.Position})
	pulled = true
	wait(10)
	if pulled then
		pulled = false
		script.Parent.Generator.Lever.Lever.Attachment.ProximityPrompt.Enabled = false
		script.Parent.Generator.Lever.Lever["Lever sound"]:Play()
		_G.TweenInstance(script.Parent.Generator.Lever.Lever,TweenInfo.new(1.2),{Position = script.Parent.Generator.Lever.LeverToGoBack.Position})
	end
end)

See that “if pulled then” statement? Could that somehow be replaced? It would be best if it repeatedly checked a value and then returned the function if changed.

What are you trying to achieve exactly? From this code, it appears that you want the lever to open when the proximity prompt is triggered, then automatically close after some amount of time. If that’s what you want, then this code looks fine. If not, then clearly explain the behavior you are trying to achieve and I can help you from there.

Also side note, you should use variables to store your objects, it makes your code much more readable and efficient.

For example, at the top of your code you can do

local Lever = script.Parent.Generator.Lever

and use this ‘Lever’ variable instead of having to use ‘script.Parent.Generator.Lever’ every single time you want to use it.

It is harder to explain than I thought it would be. I’ll try my best! Imagine you have a proximity prompt that shines 3 lights after some time when held. That would be easy to make, yes, but how do I return the whole function after the trigger ended?

Are you saying you want the function to stop/return only after the ProximityPrompt.TriggerEnded event fires, or if it fired after the ProximityPrompt.Triggered event did?

If so, the solution is simple. Let me first say this, though: when the prompt is triggered, if it will perform an action that is visible to all players, you should add a debounce so that the event threads do not interfere with each other.

What you can do is create a variable that will hold a boolean. Everytime the TriggerEnded event is triggered, check if the variable – I’ll call this variable triggerEnded – is true or not. If triggerEnded is false (not true), change it to true. Then inside the function connected to the Triggered event, check if triggerEnded is true, and if not, wait until it is true. Here’s an example:

local prompt = -- [The `ProximityPrompt`'s location.]

local debounce = false
local triggerEnded = false

prompt.TriggerEnded:Connect(function()
    if not triggerEnded then triggerEnded = true end
end)

prompt.Triggered:Connect(function()
    if debounce then return end
    debounce = true

    -- Add code here.

    if not triggerEnded then
        repeat
            task.wait()
        until triggerEnded
    end

    triggerEnded = false
    debounce = false
end)

Now, I am assuming that this ProximityPrompt is server-sided and that the action triggered will be visible to all clients, which is why I added a debounce to prevent thread collisions. If the prompt is client-sided, you can use the snippet I provided as an example. However, if the prompt is server-sided and the debounce is unnecessary, you’ll need to use a dictionary instead of the single triggerEnded variable:

local triggersEnded = {}

prompt.TriggerEnded:Connect(function(player)
    if triggersEnded[player] then return end
    triggersEnded[player] = true
end)

prompt.Triggered:Connect(function(player)
    -- Check if a thread is already running for this player.
    -- The `TriggerEnded` event couldn't have been triggered without the `Triggered` event being triggered.
    if triggersEnded[player] then return end

    -- Add code here.

    if not triggersEnded[player] then
        repeat
            task.wait()
        until triggersEnded[player]
    end

    triggersEnded[player] = nil -- You can also set this to `false`.
end)

Ok good, but I want to end the script during the code above the repeat, not after…

Why not use PromptEnded:Wait() instead a loop?

Because if someone else lets go of the prompt’s trigger, it’ll trigger for the current player and all the other players.

Oh that’s true

Chars here god…

Oh, are you saying that if the player lets go of the trigger while the code is running, you want the code to stop?

1 Like

Yes! that is exactly what I am looking for.

You can use threads. When using a thread, you can task.cancel()/coroutine.close() it at any time.

However, threads don’t yield code outside of themselves. So, in the following example, “B” would be printed first:

task.delay(5, print, "A") -- Yields 5 seconds for "A" to be outputted.
print("B")

This means that your function connected to ProximityPrompt.Triggered will return, however the code (thread) inside of it would still be running until it stops or gets cancelled in some way.

If you don’t mind the function returning and the code inside the thread still running, here’s an example for your script:

local threads = {}

prompt.TriggerEnded:Connect(function(player)
    task.cancel(threads[player])
end)

prompt.Triggered:Connect(function(player)
    threads[player] = task.spawn(function()
        -- Code here.
    end)

    -- The thread above won't yield the code down here,
    -- so the function will return while the thread runs.
end)

If you do mind the function returning, you can use a repeat until statement along with the thread.

local threads = {}

prompt.TriggerEnded:Connect(function(player)
    if not threads[player] then return end

    task.cancel(threads[player])
    threads[player] = nil
end)

prompt.Triggered:Connect(function(player)
    threads[player] = task.spawn(function()
        -- Code here.

        -- In case the thread finishes before the player lets go of the trigger.
        threads[player] = nil
    end)

    repeat -- Wait for the thread to stop running.
        task.wait()
    until not threads[player]
end)
1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.