Problem is, to my understanding, TouchEnded should fire when I’m no longer touching the part. However, in the image, I’m touching the part (blue) yet it keeps repeating 1 2 1 2
v.Touched:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
print('1')
end
end)
v.TouchEnded:Connect(function(hit)
if hit.Parent:FindFirstChild("Humanoid") then
print('2')
end
end)
If it was not colliding with anything then, from what I understand that when your moving, your legs go up and down, and your legs fire the touch event and touchended.
Because of the way touch physics work with the humanoid object, the touched event is not recommended for use without an appropriate workaround (such as creating an invisible detector some distance below the HumanoidRootPart).
For circumstances like this, you should be downcasting (shooting a raycast downward from the HumanoidRootPart). This is one of the most accurate workarounds to relying on Humanoid touch events. Fire a ray down every frame or so, verify if there’s a part and it’s an interaction error, then act.
There are other solutions here, though to address them:
Verifying if there’s a Humanoid in a Touched event is pointless in this scenario because the issue is the touch physics itself, not outside interference.
Debounce is a state boolean, not a solution.
Region3 is a bad solution here. Region3 is typically for checking a region and if a certain item is within that region. Given the image in the screenshot, a player can’t be registered in the region unless you extend the region rectangle upward.
Checking a HumanoidRootPart’s X and Z coordinates is also acceptable, but this makes the Y dimension negligible and thus allowing you to fish at any height so long as you’re in the 2D vicinity of the interaction area.
Just confirming, is this the most efficient way to do this then?
RunService.RenderStepped:Connect(function()
local NewRay = Ray.new(Character.HumanoidRootPart.CFrame.p, Vector3.new(0, -5, 0))
local Part = workspace:FindPartOnRayWithIgnoreList(NewRay, {Character})
if Part then
if Part:IsDescendantOf(Water) then
end
end
end)
Don’t use RenderStepped, use Heartbeat. RenderStepped should only be used for updates that reasonably need to be ran before a frame renders, such as camera manipulation. Code in RenderStepped can block frames from rendering and has few appropriate use cases.
As for your raycasting function, change to FindPartOnRayWithWhitelist and put only water parts in the list. The difference with whitelist is that the raycast will only check for items specified in the descendants table unlike the ignore list which checks for everything except what was specified.
-- Let's pretend you have a Folder in Workspace called "Water" that
-- contains all the water parts to be checked.
local Water = workspace.Water
RunService.Heartbeat:Connect(function ()
local downcast = Ray.new(Character.HumanoidRotPart.CFrame.Position, Vector3.new(0, -5, 0))
local part = workspace:FindPartOnRayWithWhitelist(downcast, {Water})
-- IsDescendantOf may not be necessary due to whitelist
if part and part:IsDescendantOf(Water) then
-- Perform code
end
end)
Make sure you also account for cases where your action is already active so you don’t reactivate it, whether you use the loop solely to check a player’s presence over a water region or you run your activation code in that loop.
Another note: you may experience potential issues if the water region is above the HumanoidRootPart (has a Y size of greater than 3 and the bottom surface is level with humanoid leg bottom surfaces), since the raycast may consider the character inside the part and thus not catch it with the ray.
Us, programmers had an experience like this before which some cases will trigger the event multiple times when it’s touched once, even if the character is moving. Every second your character moves, it creates multiple events at the same time which can overfill your console/script. So what I exactly do is to just have a variable and have the event disconnect when it is being touched than just having it without debounce. Debounce is really important when it comes to events that may trigger a lot of times.
for _, v in pairs(Water:GetChildren()) do
local touchended_CON
local touchended = function(p)
touchended_CON:Disconnect()
print('1')
wait(1)
touchended_CON = v.TouchEnded:Connect(touchended)
end
local touchstart_CON
local touchstart = function(p)
touchstart_CON:Disconnect()
print('2')
wait(1)
touchstart_CON = v.Touched:Connect(touchended)
end
end
Animations affect when the touched event fires. This code still has the same problems as the OP, though instead it just moves the TouchEnded connection into the Touched connection.