Touch event not firing correctly

I think there is a bug with BasePart.Touched event.

1 Like

That is not a bug, since your player is made of multiple parts.

2 Likes

this is exacly what happens lol

1 Like

That’s why the touch event isnt that good then. I’ve seen a video abou the Region3, but when trying on my place it didn’t work, so I just tried using touch on my own.

1 Like

Anyway, here is what I would do:

  • Keep track of what parts are colliding by using BasePart.Touched and BasePart.TouchEnded (no need for using regions this way)
  • Start a RunService.Heartbeat loop that:
  1. Finds what humanoids are in touch based on the parts that are colliding at the moment
  2. Applies damage to the humanoids (you might want to use deltaTime parameter from Heartbeat to give a fixed damage per second humanoid:TakeDamage(damage * deltaTime))

You can even optimize this approach by only running RunService.Heartbeat when at least one part is colliding.

1 Like

Region3 works really well, the problem could be that you maybe didn’t quite understand how to set it up. But that is what all these articles and devforum are for. If you need any extra help please ask, but I would definitely recommend looking into Region3. Use the article for help above and check out this AlvinBlox tutorial, he explains it pretty well.

1 Like

This is a interesting way to do it, but how am I going to reference the “hit” player? I tried here but it counts as an error

unknown

1 Like

I’ll take a look at his videos on Region3, thanks!

1 Like

Lets see… You could use a variable, or you could even use a table instead of a boolean. For example, if you are touching a part, add your player to a table, if nobody is touching the part, set the table variable to false, or nil.

1 Like

Ok, so I was on to this idea of using variables. I think it worked. It checks if the “isTouching” variable is true, and deals damage. If “isTouching” is false, it doesn’t deals damage.
I used the Touch and TouchEnded to know when to set the variable as true or false.

local part = script.Parent
local canDmg = true
local isTouching = false

local function damage(otherPart)
	if canDmg == true then
		local partParent = otherPart.Parent
		local hum = partParent:FindFirstChild("Humanoid")
		isTouching = true
		while true do 
			wait()
			if isTouching == true then
				hum.Health -=1
				wait(1)
			else return	
			end	
		end
	end
end	

local function stop()
	isTouching = false
end 
	

part.Touched:Connect(damage)
part.TouchEnded:Connect(stop)

```
1 Like

Ok, I think we’re almost there. Now, when I touch the part and stay, it continues dealing damage, as planned, but when it disappears and appears again, the damage stops. Or if I go where it WILL appear, when it does, the damage isn’t dealt. Probably cause the touching event doesn’t fire

2 Likes

I think I got it.

Script
local part = script.Parent
local canDmg = true
local touching = {}

part.Touched:Connect(function(hit)
	if hit.Parent and hit.Parent:FindFirstChild("Humanoid") and not table.find(touching, hit.Parent.Humanoid) then
		touching[#touching + 1] = hit.Parent.Humanoid
	end
end)

part.TouchEnded:Connect(function(hit)
	if hit.Parent and hit.Parent:FindFirstChild("Humanoid") and table.find(touching, hit.Parent.Humanoid) then
		table.remove(touching, table.find(touching, hit.Parent.Humanoid))
	end
end)

while game:GetService("RunService").Stepped:Wait() do
	for _, hum in pairs(touching) do
		if canDmg then
			hum.Health -= 5
		end
	end
	wait(1)
end
3 Likes

Try using Region3 instead of Touched because you can constantly check if the player is in the Region3. Hope it helped, there’s also plenty of videos on YouTube.

-SwedishRaptor

1 Like

Also, Touched is not recommended for that kind of stuff so uh it’s better to use Region3 anyways.

1 Like

One question: why? Also, your Region3 approach does not work if you rotate the part. You would need to use EgoMoose’s rotated Region3.

1 Like

This can be improved to:

game:GetService('RunService').Heartbeat:Connect(function(step)
	for _, hum in pairs(touching) do
		if canDmg then
			hum.Health -= 5 * step
		end
	end
end)

Now it does 5 damage per second per physics update without using wait(1).

1 Like

I wrote this code:

local damagingPart = script.Parent
local RunService = game:GetService('RunService')

local touchingParts = {}
local touchingHumanoids = {}

local updateConnection = nil

local DAMAGE_PER_SECOND = 50

local function updateTouchingHumanoids()
	local humanoids = {}
	for _, touchingPart in pairs(touchingParts) do
		local parent = touchingPart.Parent
		-- Return if the parent got destroyed
		if not parent then return end
		
		local humanoid = parent:FindFirstChild('Humanoid')
		-- Check if a humanoid exists that has not been found before
		if humanoid and not table.find(humanoids, humanoid) then
			table.insert(humanoids, humanoid)
		end
	end
	touchingHumanoids = humanoids
end

local function startUpdating()
	updateConnection = RunService.Stepped:Connect(function(_, step)
		for _, humanoid in pairs(touchingHumanoids) do
			-- Iterate through every found humanoid and deal damage
			humanoid:TakeDamage(DAMAGE_PER_SECOND * step)
		end
	end)
end

damagingPart.Touched:Connect(function(part)
	table.insert(touchingParts, part)
	updateTouchingHumanoids()
	
	-- Start updating when not updating and more than 0 humanoids interact
	if (not updateConnection or not updateConnection.Connected) and #touchingHumanoids > 0 then
		startUpdating()
	end
end)

damagingPart.TouchEnded:Connect(function(part)
	table.remove(touchingParts, table.find(touchingParts, part))
	updateTouchingHumanoids()
	
	-- Stop updating when not updating and no humanoids interact
	if #touchingHumanoids == 0 and (updateConnection and updateConnection.Connected) then
		updateConnection:Disconnect()
	end
end)

It keeps track of parts and humanoids that are touching and then applies damage every frame when more than 0 humanoids are touching. This also works when multiple humanoids are touching.

Here is a quick demo (watch the health bar in the top right of the screen):

2 Likes

I hope I’m not too late! :grinning:

local part = script.Parent
local canDmg = true

local function damage(otherPart)
	if canDmg == true then
		local partParent = otherPart.Parent
		local hum = partParent:FindFirstChildOfClass("Humanoid") or partParent.Parent:FindFirstChildOfClass("Humanoid")
		if hum then
			hum:TakeDamage(1)
		end
	end
end

local function disappear()
	part.Transparency = 1
	canDmg = false
end

local function appear()
	part.Transparency = 0.7
	canDmg = true
end

part.Touched:Connect(damage)

I believe the errors you are getting in your console is because accessories have smaller parts inside them, as children. When those smaller parts parented to the accessory touches the brick, the script attempts to find a parent, which would be the main accessory, then find a humanoid from that accessory (which obviously doesn’t exist).

A solution to this would be to check if the huumanoid exists, which has already been suggested.
However, this means that if an accessory touches the part, nothing will happen. Whether this is an expected or unexpected result, I will leave up to you.

If you do not want such parts to be omitted, then I would suggest checking both Part.Parent for the humanoid and then checking Part.Parent.Parent for it. This is, from what I have researched, the optimal method for doing so.

Remember that checking means being able to deal with errors, such as nil being returned.

As for your question about how to continuously deal damage to the player inside of the zone, your best bet would be to use simple raycasting to check for such existence. Region3 is a simpler and easier-to-grasp choice, but is much more expensive and inefficient. I’d suggest searching these up on the Roblox API, or have a look around these forums.

Good luck!

I’ve had this problem before too. It’s because you’re asking for the parent of the touched part. With accessories, it goes Player Model > Accessory > Handle and not Player Model > Handle. This means that if you get the touched parent, then you will return the Accessory rather than the Player model, so you can’t get the Humanoid.

A solution for this would be:

local function damage(otherPart)
	if canDmg == true then
		local partParent = otherPart.Parent
		if otherPart.Name == "Handle" then --Handle is the name of all accessory parts
			local hum = partParent.Parent:FindFirstChild("Humanoid") --we know that because it is a hat, we need to find the Parent of the accessory to find the player model
			if hum then
				hum.Health -= 1
			end
		else
			local hum = partParent:FindFirstChild("Humanoid")
			if hum then
				hum.Health -= 1
			end
		end
	end
end

I’ve tested this and it works fine, should work for you too :+1:

1 Like