I have a building that is supposed to take damage once if it’s touching an enemy NPC (This one is named “Brute”).
I find using TouchEnded very buggy so I’m trying to find a more efficient way of finding if the touch has ended.
What I’m trying to do is have this keep subtracting the building’s health by 25 as long as it’s still making contact with the Brute. If the Brute stops touching it then it immediately stops doing the damage.
I have literally just started working with coroutines, so if the method I’m going for is just stupid then please let me know a better way of doing this. Thank you!
The Script
while true do
local Part = script.Parent
local Attacked = Part.Parent.Attacked
local Health = Part.Parent.Health
local Found = Instance.new("NumberValue", Part)
Found.Value = 0
local DamagingBuilding = coroutine.create(function()
Part.Touched:Connect(function(Hit)
if Hit.Parent.Name == "Brute" then
Attacked.Value = true
Health.Value = Health.Value - 25
end
end)
end)
local StoppedTouching = coroutine.wrap(function()
Found.Value = 0
local Parts = Part:GetTouchingParts()
for i,v in pairs(Parts) do
if (v.Parent.Name == "Brute") then
Found.Value = Found.Value + 1
end
wait(0.1)
if Found.Value > 0 then
Attacked.Value = true
else
Attacked.Value = false
print("No longer being attacked!")
end
end
end)
wait(1.5)
if Attacked.Value == true then
coroutine.resume()
repeat
Health.Value = Health.Value - 25
wait(1.5)
until
Attacked.Changed and Attacked.Value == false
end
end
My use of coroutines might look completely stupid but that’s because all the research I’ve done on them have just confused me and I still don’t completely get them.
A coroutine can be used to run a function alongside the rest of your script. In this case you want a function to check whether a ‘brute’ is touching the building. While it is, you can wait before checking again. If it is not you can end that function
Another important consideration is whether a new touch means a new coroutine needs to be created. Since you are using a counter to see how many brutes are touching it, the answer is no. You need to keep track whether a coroutine is already running with each Touch (with only 1 brute this would still be required since .Touched can’t be relied on to fire only once)
Bearing this in mind, a viable solution could be
function checkTouch()
while Attacked.Value do -- after this loop ends, the function ends and the coroutine status becomes 'dead'
Found.Value = 0
local Parts = Part:GetTouchingParts()
for i,v in pairs(Parts) do
if (v.Parent.Name == "Brute") then
Found.Value = Found.Value + 1
end
wait(0.1)
if Found.Value > 0 then
Health.Value = Health.Value - 25
else
Attacked.Value = false
print("No longer being attacked!")
end
wait(1) -- or any other reasonable response time
end
end
local touchRoutine
local debounce
Part.Touched:Connect(function(Hit)
if debounce then return end
debounce = true
if Hit.Parent and Hit.Parent.Name == "Brute" then
if not touchRoutine or coroutine.status(touchRoutine) == "dead" then -- check if the coroutine already exists, and if so whether it's active (not 'dead')
Attacked.Value = true
touchRoutine = coroutine.create(checkTouch) -- create a new coroutine
coroutine.resume(touchRoutine) -- start running newly created routine
end
end
wait(.1)
debounce = false
end