Activating a function only once

Im scripting something very small for practice which consists of when something/someone touches that part the other one dissapears,and when touched again, it reappears but when I only touch it once, it activates multiple times while I know why, Id like to know how to stop it

(If you think I should learn more stuff before this dont be afraid to say so)

script.Parent.Touched:Connect(function(disORap)
	if game.Workspace.P2.Transparency == 0 then
		game.Workspace.P2.Transparency = 1
	else
		game.Workspace.P2.Transparency = 0
	end
	if script.parent.Touched then
		print("Detected")
	end
end)

2 Likes

You could add a disconnect as a possible solution. It will no longer trigger the touch function after you touch it the first time and it disconnects. Unless you are trying to go for a debounce, then you can use the solution below my answer.

local c = script.Parent.Touched:Connect(function(disORap)
	if game.Workspace.P2.Transparency == 0 then
		game.Workspace.P2.Transparency = 1
	else
		game.Workspace.P2.Transparency = 0
	end
	c:Disconnect()
end)

Also, you can’t really check for an event happening in the way that you tried with the if statement.

2 Likes

The debounce technique is what should be used here. For example, simply adding a BoolValue to the brick called “Touched” will provide a basic debounce. Inside the function, check whether the value is set to false at the beginning, if it is false, set it to true and at the end of the function set it back to false again. There are more complex and hardy versions of this technique and you should do some research about debouncing to help your understanding of what is actually going on.

Just to clear it out, touched is an event, do I have to change something on the function or workspace?

local runCount = 0
script.Parent.Touched:Connect(function(disORap)
    if runCount == 0 then	
        if game.Workspace.P2.Transparency == 0 then
            game.Workspace.P2.Transparency = 1
        else
            game.Workspace.P2.Transparency = 0
        end
        if script.parent.Touched then
            print("Detected")
        end
    end
    runCount = runCount + 1
end)

Works well, but now whenever I retouch it it doesnt reappear

How many times do you want it to run before it stops? Or do you not want it to stop?

I do not want it to stop

local debounce = false

script.Parent.Touched:Connect(function(hit)
if(not debounce) then
debounce = true
if game.Workspace.P2.Transparency == 0 then
game.Workspace.P2.Transparency = 1
else
game.Workspace.P2.Transparency = 0
end
print("Touched")
wait(3)
debounce = false
end
end)

Oh! Now I see what you are asking for! The answer to why that is happening is that your character has multiple parts in your body, and once each one of them touch individually, they run the function.

Here’s the newer and better code, do note that there is a grace period that you have to mess around with.

local debounce = false

script.Parent.Touched:Connect(function(disORap)
	if not debounce then
		if game.Workspace.P2.Transparency == 0 then
			game.Workspace.P2.Transparency = 1
		else
			game.Workspace.P2.Transparency = 0
		end
		if script.parent.Touched then
			print("Detected")
		end
		wait(1) -- GRACE PEROID, EDIT ME IF NEEDED
		debounce = false
	end
end)

both work perfectly (also credits to the one above) but just to clarify, is debouncing the thing that stops the code from running multiple times?

1 Like

Yes, the debounce stays false for one second, hence dis-allowing for function spam.

thx man, (also thx to deverium)

The BasePart.Touched event fires every frame when 2 objects in contact move, given your client is running at 60FPS, it’ll fire every 1/60 seconds which in one second, is 60 times.

Non-relative debounce mechanism is typically implemented in functions through

if bool then bool = false  ... wait(n) bool = true 

or similar paradigms used within the passed callback to BasePart.Touched.Connect (which you would pass as BasePart.Touch:Connect(f)), this prevents the callback passed to the listener executing too many times in a period of time.

-- example
local deb;

local function onTouched(param)
    if not deb then -- if the code hasn't run already or the required time has passed for it to be allowed to run again...
        deb = true -- so that the next time the callback executes, the first condition in the function will return false, effectively preventing the code running again unless enough time has passed 
        -- since listeners are called in separate threads,  depending on how fast the Touched event fires, the code will run too frequently without anything stopping it in normal situations
        --// run code
        wait(2) -- a "cooldown" before the code can run again
        deb = false -- approximately* 2 seconds have passed, allow the code to run again the next time the event fires 
    end
end

Part.Touched:Connect(onToucehd)

* it takes time for a Lua thread to resume after you call wait(), never assume it will yield for an exact amount of time or have parts of gameplay depend on its accuracy (though for general use like in this case, it should be alright).

3 Likes

Thaks for the explanation, Ill take it into consideration