How to deal with inconsistent touched events

I want to create a system where players run through gates and get awarded with coins etc. I am currently using CollectionService as I have 500 gates.

In my game players travel at high walk speeds at over 10k+. When a speed of about 2k or over is reached the touched event on the level gates sometimes doesn’t register.
This is my script:

local CollectionService = game:GetService("CollectionService")
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local events = ReplicatedStorage:WaitForChild("events")
local gatePassed = events:WaitForChild("gatePassed")



local function onHit(hit,tagged)
	if hit.Parent:FindFirstChild("Humanoid")then
		local character = hit.Parent
		local player = Players:GetPlayerFromCharacter(character)
		if player then
			local gateNumber = tonumber(tagged.SurfaceGui.TextLabel.Text)
			if gateNumber == 500 then
				character.HumanoidRootPart.Velocity = Vector3.new(0, 0, 0)
			end
			local leaderstats = player:FindFirstChild("leaderstats")
			local coins = leaderstats:FindFirstChild("Coins")
			if gateNumber < 16 then
				coins.Value = coins.Value + 1
			elseif gateNumber >= 16 and gateNumber < 46 then
				coins.Value = coins.Value + 3
			elseif gateNumber >= 46 and gateNumber < 106 then
				coins.Value = coins.Value + 5
			elseif gateNumber >= 106 and gateNumber < 226 then
				coins.Value = coins.Value + 10
			elseif gateNumber >= 226 then
				coins.Value = coins.Value + 15
			end
			gatePassed:FireClient(player)
			tagged:Destroy()
		end
	end
end

local function onInstanceAdded(instance)
	instance.Touched:Connect(function(hit)
		onHit(hit,instance)
	end)
end

local taggedGate = CollectionService:GetTagged('winGate')
for _, tagged in pairs(taggedGate) do
	onInstanceAdded(tagged)
end

CollectionService:GetInstanceAddedSignal('winGate'):Connect(onInstanceAdded)

After researching this I have seen raycasting to be a possible solution but I am unsure how I would make this work with 500 parts. Any suggestions would be appreciated.

1 Like

Touch event is unreliable * (as I’m sure everyone is aware by now) and should only be used for low-precision tasks. For something accurate, raycasting is one option, but what you’ll probably want to use is something related to OverlapParams. The easiest one to use in your case would be GetPartsInPart. It will return a table of parts that are intercepting the given part. Note that it won’t trigger on parts that are simply touching faces (something this precise would only occur when working with exact positions and anchored parts). But that’s not really important as it’s basically exactly how you’d want it to work. You can use the parameters to define a blacklist if you’d like.

Though it’s not a one-to-one replacement as this is a function and not an event. It’s possible to write a custom function to replicate how the Touch event works though, while using this system.

* The touch event is only unreliable server-side.

(The touch event can also be exploited as the client can technically trigger a touch event or ClickDetector event at any distance.)

2 Likes

What would you recommend for the best option to constantly run this function. Would it be something like heartbeat?

i think a better option would be raycasting

How would I implement raycasting with 500 parts?
Could I somehow make the ray come from the player instead?

yes that would be what you would do

I’m struggling to figure this out, I’ve raycasted from the players head in the direction they’re looking in whilst also updating it with a while wait() loop to change with the players direction but I still can’t get this working. Also if the player goes at speeds of 10k+, couldn’t there still be a possibility it misses it due to the wait()?

in theory yes but unlikely if we were to raycast every frame

Have you considered using modules (like ZonePlus)?

That doesn’t seem to keep up with the high speeds either.

I’ve found a solution utilizing the Raycast Hitbox module, I made a player hitbox where the rays come from, this seems to work for every gate passed.