How can I make a Touched Event fire only once?

hello scripters! I was wondering, is there a way to make part.Touched fire only once as the player is continuously touching it?

this meaning, can the player stand on top of a part, but only have the Touched event fire once? regularly, the touched event would fire multiple times if the player continued to stand on the part

3 Likes
--disconnect the event on touch
local connection 
connection = Part.Touched:Connect(function(hit)
	connection:Disconnect()
	--code
end)

--or use a debounce
local debounce = false
Part.Touched:Connect(function(hit)
	if debounce then return end 
	debounce = true 
	--code
end)
8 Likes

In addition to the above:

Part.Touched:Wait()
4 Likes

how could I detect if other players touch the part using the connection?

I’m trying to make a script that make a large hexagon and damages everyone in it, using the connection method only damaged the first person it touched.

The debounces method sounds better for this:

local Players = game:GetService("Players")

local debounces = {}
local connection
connection = Part.Touched:Connect(function(hit)
	local Player = Players:GetPlayerFromCharacter(hit.Parent)
	if not Player then return end --ignore if not player 
	if table.find(debounces, Player) then return end --player already touched
	--code 
	table.insert(debounces, Player)
	--disconnect the connection inside or outside the function when you want it to stop completely
	--connection:Disconnect() 
end)
2 Likes

thank you so much! and one last thing, would I be able to get all of the characters and humanoids of the players from the table? and if so, would I do it under table.find or table.insert.

I dont use tables that often so, sorry for the dumb questions

The table contains all the players who touched, although if you want it to store the characters just do table.find(debounces, hit.Parent) and table.insert(debounces, hit.Parent).

and to loop through each of them:

for _, character in pairs(debounces) do 
	print(character)
end
1 Like

Alternatively, you can simply fetch the Character and Humanoid through the players stored in the table.

for _, player in ipairs(debounces) do
    local Character = player.Character
    if Character then
      local Humanoid = Character:WaitForChild("Humanoid")
    end
end
2 Likes

thank you so much! saved me about an hour of figuring out how to write this part

I think using FindFirstChild is better for this:

local Humanoid = Character:FindFirstChild("Humanoid")
if Humanoid then 
--run code
end

because if one humanoid is missing, it will cause an infinite yield which will prevent the script execution for every other player.

2 Likes

@AbiZinho @NyrionDev

sorry to bother you guys again, I just have one small problem. I got a script down but when I test it, the dummy’s take random amounts of damage, not the damage I want them to take.

here’s the code I have so far:

-- services, variables and functions
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local TweenService = game:GetService("TweenService")

local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://"

local connection

local debounces = {}
local connection


ReplicatedStorage.WandaRemotes.WandaHex.OnServerEvent:Connect(function(player)
	local character = player.Character
	local hex = ReplicatedStorage.WandaPowers.WandaHex:Clone()
	
	character.HumanoidRootPart.Anchored = true
	
	local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Circular, Enum.EasingDirection.Out)
	local goal = {}
	goal.Size = Vector3.new(60,20,57)
	goal.Position = character.HumanoidRootPart.Position + Vector3.new(0,0,0)

	
	local tween = TweenService:Create(hex, tweenInfo, goal)
	
	hex.Position = character.HumanoidRootPart.Position + Vector3.new(0,4,0)
	hex.Parent = workspace
	wait(1)
	tween:Play()
	
	connection = hex.Touched:Connect(function(target)
		if target.Parent:IsA("Accessory") then
			print("touching accessory")
			local character = target.Parent.Parent
			if not character then return end 
			if table.find(debounces, character) then return end 

			table.insert(debounces, character)
			
			for _, player in pairs(debounces) do
				if character then
					local humanoid = character:FindFirstChild("Humanoid")
					if humanoid then
						humanoid:TakeDamage(20)
					end
				end
			end
			
		--elseif target.Parent.Humanoid then
			
		end
	end)
end)

I tried using connection:Disconnect() but that only makes one player take damage, and when I don’t use it, all players take damage, but they take random amounts of it. I probably wrote it wrong since I have 0 experience with tables, your help would be appreciated!

the reason I’m checking for accessories is because the characters have custom 3d clothing over their bodies and when I dont check for accessories it gives me errors for each piece of clothing and just fills up my outputs

In this case, you do not need to iterate through the debounces table using a for loop, since that loops through all players, meaning players who are already in the hexagon will deal more damage unnecessarily. Instead, just replace that with your TakeDamage code:

local connection

local debounces = {}
local connection


ReplicatedStorage.WandaRemotes.WandaHex.OnServerEvent:Connect(function(player)
	local character = player.Character
	local hex = ReplicatedStorage.WandaPowers.WandaHex:Clone()
	
	character.HumanoidRootPart.Anchored = true
	
	local tweenInfo = TweenInfo.new(1, Enum.EasingStyle.Circular, Enum.EasingDirection.Out)
	local goal = {}
	goal.Size = Vector3.new(60,20,57)
	goal.Position = character.HumanoidRootPart.Position + Vector3.new(0,0,0)

	
	local tween = TweenService:Create(hex, tweenInfo, goal)
	
	hex.Position = character.HumanoidRootPart.Position + Vector3.new(0,4,0)
	hex.Parent = workspace
	wait(1)
	tween:Play()
	
	connection = hex.Touched:Connect(function(target)
		if target.Parent:IsA("Accessory") then
			print("touching accessory")
			local character = target.Parent.Parent
			if not character then return end 
			if table.find(debounces, character) then return end 

			table.insert(debounces, character)
			
            -- changed code starts here
			local humanoid = character:FindFirstChild("Humanoid")
			if humanoid then
				humanoid:TakeDamage(20)
			end
             -- changed code ends here
			
		--elseif target.Parent.Humanoid then
			
		end
	end)
end)
1 Like

You are looping through all the players every time 1 player touches the part. Instead do hit.Parent.Humanoid:TakeDamage(20) which refers to the humanoid who touched the part at the specific moment.

1 Like