Twitchy Touches Workaround

I’ve been planning my own proximity system and had problems with touched events that I can only explain as twitching. Visually, it looks to work as intended, but I noticed that the parts get disconnected unexpectedly. Touchended and touched are fired in rapid succession, all in a single render cycle. This happens both when I press and release the spacebar to jump, and sometimes as I run around the object.
Since it’s fired so fast, changes can’t be seen unless you print to the console.

It’s set to weld a sphere around the player when they load.

local root = game.Players.LocalPlayer.CharacterAdded:Wait():WaitForChild("HumanoidRootPart")

local prox = Instance.new("Part")
prox.CanCollide =  false
prox.CastShadow = false
prox.Massless = true
prox.Material = Enum.Material.ForceField
prox.Position = root.Position
prox.Shape = Enum.PartType.Ball
prox.Size = Vector3.new(32, 32, 32)
prox.Parent = workspace

local weld = Instance.new("WeldConstraint")
weld.Part0 = prox
weld.Part1 = root
weld.Parent = workspace

So instead of attaching to events like this:

prox.Touched:Connect(function (hit)
	if hit.Name == "Trigger" then
		print("Touched "..hit.Name)
		hit.Material = Enum.Material.Neon
	end
end)

prox.TouchEnded:Connect(function (hit)
	if hit.Name == "Trigger" then
		hit.Material = Enum.Material.Plastic
	end
end)

I’ve had to resort to something a bit more complicated.

local touches = {}

local function WhatWeWant(obj) return obj.Name == "Trigger" end

prox.Touched:Connect(function (hit)
	-- Check requirements
	if not WhatWeWant(hit) then return end
	
	if touches[hit] then
		-- Twitch detected
		touches[hit] = touches[hit] + 1
		return
	else
		-- Initialize count
		touches[hit] = 1
	end
	
	-- Begin touch
	print("Touched "..hit.Name)
	hit.Material = Enum.Material.Neon
end)

prox.TouchEnded:Connect(function (hit)
	-- Check requirements
	if not WhatWeWant(hit) then return end
	
	-- Give time to twitch
	wait()
	
	-- Adjust touch count
	touches[hit] = touches[hit] - 1
	
	-- Sink all but last event
	if 0 < touches[hit] then return end
	
	-- Reset touches
	touches[hit] = nil
	
	-- End touch
	print("Touchended "..hit.Name)
	hit.Material = Enum.Material.Marble
end)

Download the place here. There are two scripts located in ReplicatedStorage, basic and fixed, but the one named basic is disabled.

Is this the best way to go about this or am I missing something?

1 Like