I think there is a bug with BasePart.Touched
event.
That is not a bug, since your player is made of multiple parts.
this is exacly what happens lol
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.
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:
- Finds what humanoids are in touch based on the parts that are colliding at the moment
- 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.
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.
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
I’ll take a look at his videos on Region3, thanks!
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.
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)
```
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
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
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
Also, Touched is not recommended for that kind of stuff so uh it’s better to use Region3 anyways.
One question: why? Also, your Region3 approach does not work if you rotate the part. You would need to use EgoMoose’s rotated Region3.
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).
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):
I hope I’m not too late!
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