Need better script for detecting player touching part

So I’m working on making a robust script for detection of players touching a part. The script seems to work fine while the player is touching but not moving but once moving and touching the part it runs too often. I’ve tried a few things but I figure it’s something to do with debouncing when multiple parts touching at the same time.

robloxapp-20230902-1235152.wmv (3.1 MB)

-- Basic damage part script for continuous damage
local damagePart = script.Parent
local damageRate = 10
local damageCooldown = 1
local isInDamageZone = false -- Start with the player not in the damage zone

local function takeDamage(humanoid)
	while isInDamageZone do
		humanoid:TakeDamage(damageRate)
		wait(damageCooldown)
	end
end

damagePart.Touched:Connect(function(otherPart)
	local char = otherPart.Parent
	local hum = char:FindFirstChild("Humanoid")
	local player = game.Players:GetPlayerFromCharacter(char)

	if hum and not isInDamageZone then
		local touchingParts = damagePart:GetTouchingParts()

		for _, part in ipairs(touchingParts) do
			if part:IsDescendantOf(char) then
				-- Player has entered the damage zone
				isInDamageZone = true
				takeDamage(hum)
				break
			end
		end
	end
end)

damagePart.TouchEnded:Connect(function(otherPart)
	local char = otherPart.Parent
	local hum = char:FindFirstChild("Humanoid")

	if hum then
		-- Player has left the damage zone
		isInDamageZone = false
	end
end)

2 Likes

A debounce should work.

Code:

-- Basic damage part script for continuous damage
local damagePart = script.Parent

--//Controls
local damageRate = 10
local damageCooldown = 1
local damageDebounce = false

--//Tables
local humanoidsTouching = {}

--//Functions
local function takeDamage(humanoid)
	while table.find(humanoidsTouching, humanoid) do
		humanoid:TakeDamage(damageRate)
		task.wait(damageCooldown)
	end
end

damagePart.Touched:Connect(function(otherPart)
	local char = otherPart.Parent
	local hum = char:FindFirstChild("Humanoid")
	
	if not hum or table.find(humanoidsTouching, hum) or damageDebounce then
		return
	end
	
	damageDebounce = true
	
	table.insert(humanoidsTouching, hum)
	takeDamage(hum)
	
	task.wait(damageCooldown)
	damageDebounce = false
end)

damagePart.TouchEnded:Connect(function(otherPart)
	local char = otherPart.Parent
	local hum = char:FindFirstChild("Humanoid")
	
	if not hum then
		return
	end
	
	local humanoidFound = table.find(humanoidsTouching, hum)
	
	if humanoidFound then
		table.remove(humanoidsTouching, humanoidFound)
	end
end)
1 Like

Not quite. if I stand still inside the dangerPart it doesn’t run continuously.

1 Like

You can just use a while loop to do this (does not need TouchEnded)

local function takeDamage(humanoid)
		humanoid:TakeDamage(damageRate)
		task.wait(damageCooldown)
end

while true do
	wait()
	local parts = damagePart:GetTouchingParts()
	for i1, otherPart in pairs(parts) do
		local char = otherPart.Parent
		local hum = char:FindFirstChild("Humanoid")
		local player = game.Players:GetPlayerFromCharacter(char)
		if player and hum and char then
			takedamage(hum)
			break
		end
	end
end

Forgot to check if there are any more parts touching before I removed the humanoid from the table.

Code:

-- Basic damage part script for continuous damage
local damagePart = script.Parent

--//Controls
local damageRate = 10
local damageCooldown = 1
local damageDebounce = false

--//Tables
local humanoidsTouching = {}

--//Functions
local function takeDamage(humanoid)
	while table.find(humanoidsTouching, humanoid) do
		humanoid:TakeDamage(damageRate)
		task.wait(damageCooldown)
	end
end

damagePart.Touched:Connect(function(otherPart)
	local char = otherPart.Parent
	local hum = char:FindFirstChild("Humanoid")

	if not hum or table.find(humanoidsTouching, hum) or damageDebounce then
		return
	end

	damageDebounce = true

	table.insert(humanoidsTouching, hum)
	takeDamage(hum)

	task.wait(damageCooldown)
	damageDebounce = false
end)

damagePart.TouchEnded:Connect(function(otherPart)
	local char = otherPart.Parent
	local hum = char:FindFirstChild("Humanoid")

	if not hum then
		return
	end

	local humanoidFound = table.find(humanoidsTouching, hum)
	
	if not humanoidFound then
		return
	end
	
	local partsTouching = damagePart:GetTouchingParts()
	
	for i, part in ipairs(partsTouching) do
		if part.Parent == char then
			return
		end
	end
	
	table.remove(humanoidsTouching, humanoidFound)
end)

Works great until I die then I get…

Check the new code, I made a typo by putting hum instead of humanoidFound.

Still close, sorry I don’t know how to upload a video properly nor have the editing ability.

robloxapp-20230902-1353235.wmv (4.3 MB)

I used :IsDescendantOf instead of .Parent. This should work.

Code:

-- Basic damage part script for continuous damage
local damagePart = script.Parent

--//Controls
local damageRate = 10
local damageCooldown = 1
local damageDebounce = false

--//Tables
local humanoidsTouching = {}

--//Functions
local function takeDamage(humanoid)
	while table.find(humanoidsTouching, humanoid) do
		humanoid:TakeDamage(damageRate)
		task.wait(damageCooldown)
	end
end

damagePart.Touched:Connect(function(otherPart)
	local char = otherPart.Parent
	local hum = char:FindFirstChild("Humanoid")

	if not hum or table.find(humanoidsTouching, hum) or damageDebounce then
		return
	end

	damageDebounce = true

	table.insert(humanoidsTouching, hum)
	takeDamage(hum)

	task.wait(damageCooldown)
	damageDebounce = false
end)

damagePart.TouchEnded:Connect(function(otherPart)
	local char = otherPart.Parent
	local hum = char:FindFirstChild("Humanoid")

	if not hum then
		return
	end

	local humanoidFound = table.find(humanoidsTouching, hum)

	if not humanoidFound then
		return
	end

	local partsTouching = damagePart:GetTouchingParts()

	for i, part in ipairs(partsTouching) do
		if part:IsDescendantOf(char) then
			return
		end
	end

	table.remove(humanoidsTouching, humanoidFound)
end)

I’m extremely tired right now. The script you wrote starts the damage and it continues when not touching the part. when I retouch the part it stops taking damage. It like toggles between on and off.

Hmm, another approach would be to use a while loop like @neweve2323 did.

Code:

--//Variables
local damagePart = script.Parent

--//Controls
local damageRate = 10
local damageCooldown = 1

--//Tables
local humanoidCache = {}

--//Functions
while task.wait(damageCooldown) do
	local touchingParts = damagePart:GetTouchingParts()
	
	for i, part in ipairs(touchingParts) do
		local humanoid = part.Parent:FindFirstChildWhichIsA("Humanoid")
		
		if humanoid and not humanoidCache[humanoid] then
			humanoidCache[humanoid] = true
			
			humanoid:TakeDamage(damageRate)
		end
	end
	
	table.clear(humanoidCache)
end

Take a rest then, don’t lose sleep over Roblox lol.

1 Like

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