Functions in .Touched event firing 30 seconds later

Hello!

I’ve had this problem plaguing my game for ages now, and it’s driving me insane that I don’t know how to fix it. The main point of the game is crashing cars, and the crash mechanics I have laid down are fairly solid. The issue is when cars crash into each other, they’re supposed to break apart and explode. Well, it does that, but then it keeps doing it. Sometimes for ever 30 seconds after the actual crash happened.

Video example: https://youtu.be/eX6seLGeWL4

The script that runs this is as follows (sorry if the formatting is bad, this isn’t the whole script. It’s only the parts that have to do with inter-car collisions)

local connections = {}

for i, v in pairs(car:GetChildren()) do
    connections[v] = v.Touched:Connect(function(hit)
			onTouched(hit, v)
		end)
 end
function onTouched(hit, hitter)
    if not hit.Parent or not hit.Parent.Parent or hit.Parent.Name ~= "Car" or hit.Parent == car then return end

local function awardMoney()
	local cc = player.leaderstats["Crash Cash"]
	local isPrem = player.MembershipType
	local isVip = player:FindFirstChild("isVip")
	
	if isPrem == Enum.MembershipType.Premium and isVip ~= nil then
		cc.Value = cc.Value + (4 * game.Workspace.Assets.CashMultiplier.Value)
	elseif isPrem == Enum.MembershipType.Premium or isVip ~= nil then
		cc.Value = cc.Value + (2 * game.Workspace.Assets.CashMultiplier.Value)
	else
		cc.Value = cc.Value + (1 * game.Workspace.Assets.CashMultiplier.Value)
	end	
end

local yourVel = car.Parent.Config.Velocity.Value
if yourVel >= breakSpeed then
	awardMoney()
	hit:BreakJoints()
	
	if playSound then
		playSound = false
		local sound = Instance.new("Sound", hit)
		sound.SoundId = smashSounds[rand:NextInteger(1, 2)]
		sound.Volume = 0.75
		sound:Play() 
		game.Debris:AddItem(sound, sound.TimeLength + 0.5)
		wait(0.1)
		playSound = true
	end	
	
	if yourVel >= explodeSpeed and Explode then 
		Explode = false
		if connections[hitter] ~= nil then
			connections[hitter]:Disconnect()
			connections[hitter] = nil
		end
		local f = Instance.new("Fire"); f.Parent = hit
		local boom = Instance.new("Explosion")
		local sound = Instance.new("Sound"); sound.Parent = hit
		boom.BlastRadius = 1
		boom.Position = hit.Position 
		boom.Parent = hit
		sound.SoundId = "rbxassetid://142070127"
		sound.Volume = 1
		sound:Play()
		game:GetService("Debris"):AddItem(sound, sound.TimeLength + 0.5)
		wait()
		Explode = true	
	end
end

end

Please help! This issue is driving me nuts!

I’d investigate why the second round of explosions happens exactly when the white car touches down far away

And see if what the white car does later correlates to following explosions

Edit:
It’s not that your Touched events are latent, those are happening on time
It’s Touched events happening that you weren’t expecting

I added a lot of print statements to see what was going on and it’s just wayyyyy too many .Touched events firing all at once to the point the server can’t keep up. Any ideas on how to slow that down a bit?

When creating the touched events for each car part, also create a debounce variable just above the connection within the for loop. In the touched event, check if this debounce variable is false, and if so, change that debounce to true, and trigger whatever effect you want.

Use a debounce, or better yet use EgoMooses Rotated Region3 Module instead of .Touched

IMO .Touched isn’t that good for detecting collisions (Its also really easy for exploiters to abuse it), so its much better to use an alternative.

For instance, if you spam jump on a part, sometimes its .Touched event won’t even fire, despite you clearly touching it.

Updating a Region3 to constantly match the vehicles CFrame is going to be extremely expensive.

In reality, the best thing to do ( to achieve the perfect effect ) would be to create some kind of collision prediction system. One that can detect the closest two points between two cars, and create damage near those points on both vehicles just before a high speed impact.

EgoMoose’s module is actually pretty efficient and isn’t as expensive as you would think.

Depending on the hitbox’s size, you probably won’t be needing to run it every frame, either.
At a drastic scale maybe every .Stepped or Heartbeat.

As I said before, .Touched is too buggy and easily abused by exploiters.
The best solution if your really worried about performance is using :GetTouchingParts().

In comparison to the Region3, how expensive would it be to create that effect through Raycasting?

Raycasts are actually fairly lightweight depending on their length.
The longer that they are, the more performance they take, so if you just keep the raycasts fairly small (maybe 50 studs at max), you shouldn’t experience any issues.

Compared to region3, the raycasts will win easily.

Which do you think would be more accurate?

The more Rays you use, the more accurate it will be. If you make ray casts all around the car, it should be as accurate as a Region3.

So I’m gonna start trying with Region3.

Would it be too taxing to run it within a RunService.Stepped function? Or should I have it run another way?

.Stepped might be a little overkill.
I recommend just experimenting with different times to see what feels good, as I sadly on mobile so I’m unable to test it for you.