How would you make a touched event happen only once and happen again if touched again

  1. What do you want to achieve? Keep it simple and clear!

I want a button that prints “hi” when stepped on. It should only happen once, and it can happen again after being stepped on again.

  1. What is the issue? Include screenshots / videos if possible!

The issue is that it prints multiple times whenever the player walks on it.

Video of issue:

  1. What solutions have you tried so far? Did you look for solutions on the Developer Hub?

I saw that people normally use debounces but they just slow down the printing.
I tried to add a table system where it adds the player’s character that touched the button in a table thats checked whenever the character touches the button and removes it if not touched, but it had the same multiple printing issue before.

My code:

local button = script.Parent

button.Touched:Connect(function(p)
	if p.Parent:FindFirstChild("Humanoid") then
		local char = p.Parent
		print("hi")
	end
end)
1 Like

add a debounce im assuming ur problem is it prints a load of times this is because the listener fires a bunch of times because its very fast so a debounce will look like this

local button = script.Parent
local Debounce = 0
button.Touched:Connect(function(p)
    if tick() >= Debounce then 
        Debounce = tick() +1
	    if p.Parent:FindFirstChild("Humanoid") then
		    local char = p.Parent
		    print("hi")
	    end
    end 
end)

tick() gets the current time in seconds

every time the code runs we add one to the value of time and make the code check if its past that time so it can run again and add another 1

1 Like

The problem is that it still prints when the player moves on the button

so you want the character to physically get off the part and then print again once it gets back on?

if this is the case then do characters foot.touched

Yes thats what I’m trying to make

You could use BasePart.TouchEnded to determine when the player gets off the part and use that to reset the debounce.

1 Like

do it based of the characters feet so when it hits the button print hi then dont let the code run again until it hits the baseplate or some other part

I tried that but it detects every single part of the character

Try this:

local button = script.Parent

local touchFunction = button.Touched:Connect(function(p)	
    if p.Parent:FindFirstChild("Humanoid") then
	    local char = p.Parent
	    print("hi")
        touchFunction:Disconnect()
	end
end)

I tried that before but it only does it once and you can’t do it ever again

Well without typing actual code ill try to explain a simple methodology to this as best I could.

In the touched function you determine which player steps on the part, by just checking the parts ancestor. From there you can assign a denounce value to that particular player regarding that particular part. In short it will represent that the player is currently on the part. You then have a touch ended function that fires when a player leaves the part. In the same manner you get the ancestor of the part and if it happens to be a player you reset the debounce, allowing the action to run again.

In short the moment the player touches the part, you lock the action from happening again until the player leaves the part and the touch ended function fires.

The problem is that the touchended event fires when the player walks so it prints multiple times

That’s likely due to the fact that the walking animation causes the players feet to step off the ground. A hacky solution would be to just use a taller invisible block for the touch/touchended events. Instead though you could look into shooting rays from the player and/or the block, of even possibly using region3 to detect whether a player is in an area.

(Sorry for the late reply, I was eating dinner) I misread your post, sorry! You can probably work something out with magnitude to tell if the player is still close to it or not.

I tried those ideas and it works, but I only want it to fire once.

Same logic though, you simply need a denounce to turn false once a player is on the part / in the region and then turn true when they leave.

I think i get it now. I could try using a bool value and change it to cause an event

A great way to achieve this while still using the “.Touched” and “.TouchEnded” events is as follows. Firstly, the part’s “.TouchEnded” connection should only be created when its “.Touched” connection is fired. Secondly, the “hit” part which results in both events firing, should be checked for equality, that way we can determine exactly when the “hit” part began/stopped touching some other part.

https://gyazo.com/c16333ae56229add25ef9361b45a4582

local players = game:GetService("Players")

local part = script.Parent

part.Touched:Connect(function(hitStart)
	local hitModel = hitStart:FindFirstAncestorOfClass("Model")
	if hitModel then
		local hitPlayer = players:GetPlayerFromCharacter(hitModel)
		if hitPlayer then
			print(hitStart.Name.." touched part.")
			local connection do
				connection = part.TouchEnded:Connect(function(hitEnd)
					if hitStart == hitEnd then
						local hitModel = hitEnd:FindFirstAncestorOfClass("Model")
						if hitModel then
							local hitPlayer = players:GetPlayerFromCharacter(hitModel)
							if hitPlayer then
								print(hitEnd.Name.." stopped touching part.")
								connection:Disconnect()
							end
						end
					end
				end)
			end
		end
	end
end)
2 Likes