Car Crash System not functioning properly

I made car crash system, but when the player drives the car, the wheels break off. This may be happening because my script detects whenever a part from the car is touched, therefore breaking off.

https://gyazo.com/b89a1f480ecfc37497393a22424582ea

How would I make the wheels unable to break when normally driving? Only being breakable when hitting an object.

If you need any code, I will provide some.

Could you paste your entire script?

for i, v in pairs(script.Parent:GetDescendants()) do
	if v:IsA("Part") or v:IsA("UnionOperation") or v:IsA("MeshPart") then
		v.Touched:Connect(function(hit)
			local isValidHit = validHit(hit, v)
			local isValidVehicle = validVehicle(hit)
			
			if isValidHit then
				local isValidVelocity = validVelocity(hit, v)
				
				if isValidVelocity then
					if not crashed then
						crashed = true
							
						crashParticles(v)
						crashSound(v)
						crashVelocity(v)

						v:BreakJoints()
						
						task.delay(.75, function()
							crashed = false
						end)
					end
				end
			end
			
			if isValidVehicle then
				local isValidVelocity = validVelocity(hit, v)

				if isValidVelocity then
					if not pvp then
						pvp = true

						crashParticles(hit)
						crashSound(hit)
						crashVelocity(hit)

						hit:BreakJoints()

						task.delay(1.25, function()
							pvp = false
						end)
					end
				end
			end
		end)
	end
end

Try this:

local mainBody = script.Parent.PrimaryPart --//Change if needed

for i, v in pairs(script.Parent:GetDescendants()) do
	if v:IsA("Part") or v:IsA("UnionOperation") or v:IsA("MeshPart") then
		v.Touched:Connect(function(hit)
			local isValidHit = validHit(hit, v)
			local isValidVehicle = validVehicle(hit)

			if isValidHit then
				local isValidVelocity = validVelocity(hit, v)

				if isValidVelocity and not crashed then
					if mainBody.AssemblyLinearVelocity.Magnitude <= 0 and v.Name == "MyWheelName" then
						return
					end
					
					crashed = true

					crashParticles(v)
					crashSound(v)
					crashVelocity(v)

					v:BreakJoints()

					task.delay(.75, function()
						crashed = false
					end)
				end
			end

			if isValidVehicle then
				local isValidVelocity = validVelocity(hit, v)

				if isValidVelocity and not pvp then	
					pvp = true

					crashParticles(hit)
					crashSound(hit)
					crashVelocity(hit)

					hit:BreakJoints()

					task.delay(1.25, function()
						pvp = false
					end)
				end
			end
		end)
	end
end

This works, but I’m unable to break the wheels when crashing into an object

Could you tell me what this prints when you crash the car?

local mainBody = script.Parent.PrimaryPart --//Change if needed

for i, v in pairs(script.Parent:GetDescendants()) do
	if v:IsA("Part") or v:IsA("UnionOperation") or v:IsA("MeshPart") then
		v.Touched:Connect(function(hit)
			local isValidHit = validHit(hit, v)
			local isValidVehicle = validVehicle(hit)

			if isValidHit then
				local isValidVelocity = validVelocity(hit, v)

				if isValidVelocity and not crashed then
					if v.Name == "MyWheelName" then
						print(mainBody.AssemblyLinearVelocity.Magnitude)
						
						return
					end

					crashed = true

					crashParticles(v)
					crashSound(v)
					crashVelocity(v)

					v:BreakJoints()

					task.delay(.75, function()
						crashed = false
					end)
				end
			end

			if isValidVehicle then
				local isValidVelocity = validVelocity(hit, v)

				if isValidVelocity and not pvp then	
					pvp = true

					crashParticles(hit)
					crashSound(hit)
					crashVelocity(hit)

					hit:BreakJoints()

					task.delay(1.25, function()
						pvp = false
					end)
				end
			end
		end)
	end
end

Also, could you post the entire script?

The number it prints depends on how fast the car goes. It seems like the minimal is 30 though

local function crashParticles(part)
	if part then
		for i, particle in pairs(script:GetChildren()) do
			if particle:IsA("ParticleEmitter") then
				local newParticle = particle:Clone()
				newParticle.Enabled = false
				newParticle.Parent = part
				newParticle:Emit(6)
				debris:AddItem(newParticle, .25)
			end
		end
	else
		warn(script.Name.. " -> crashParticles Function: part argument is nil.")
	end
end

local function crashSound(part)
	if part then
		local getSounds = sounds:GetChildren()
		local randomCrashSound = getSounds[math.random(1, #getSounds)]:Clone()
		randomCrashSound.Parent = part
		randomCrashSound:Play()

		debris:AddItem(randomCrashSound, 4)
	else
		warn(script.Name.. " -> crashSound Function: part argument is nil.")
	end
end

local function crashVelocity(part)
	part.CanCollide = false
	part.Anchored = false
	
	local bodyVelocity = Instance.new("BodyVelocity", part)
	bodyVelocity.P = 250
	bodyVelocity.MaxForce = Vector3.new(9999, 9999, 9999)
	bodyVelocity.Velocity = Vector3.new(20, 20, 20)

	debris:AddItem(bodyVelocity, .25)
end

local function validVelocity(hit, part)
	if part.Velocity.Magnitude > hit.Velocity.Magnitude + 30 or hit.Velocity.Magnitude > part.Velocity.Magnitude + 65 then
		return true
	end

	return false
end

local function validHit(hit, part)
	if hit and part then
		if hit.Parent then
			if not table.find(possibleParents, hit.Parent.Name) and not table.find(ignoreHit, hit.Name) and not table.find(ignorePart, part.Name) then
				if not hit.Parent:FindFirstChild("Humanoid") and hit.CanCollide == true and not game.Players:FindFirstChild(hit.Parent.Name) then
					if hit:IsA("Part") or hit:IsA("UnionOperation") or hit:IsA("MeshPart") or hit:IsA("WedgePart") or hit:IsA("CornerWedgePart") then
						return true
					end
				end
			end

			return false
		else
			warn(script.Name.. " -> validHit Function: hit.Parent = nil.")
		end
	else
		warn(script.Name.. " -> validHit Function: One of two arguments is nil.")
	end
end

local function validVehicle(hit)
	if hit then
		if hit.Parent then
			if table.find(insideParents, hit.Parent.Name) then
				local vehicleName = hit.Parent.Parent.Parent.Name

				if script.Parent.Name ~= vehicleName then
					return true
				end
			elseif table.find(outsideParents, hit.Parent.Name) then
				local vehicleName = hit.Parent.Parent.Name

				if script.Parent.Name ~= vehicleName then
					return true
				end
			end
			
			return false
		else
			warn(script.Name.. " -> validVehicle Function: hit.Parent = nil.")
		end
	else
		warn(script.Name.. " -> validVehicle Function: Hit does not exist.")
	end
end

--//Script

for i, v in pairs(script.Parent:GetDescendants()) do
	if v:IsA("Part") or v:IsA("UnionOperation") or v:IsA("MeshPart") then
		v.Touched:Connect(function(hit)
			local isValidHit = validHit(hit, v)
			local isValidVehicle = validVehicle(hit)

			if isValidHit then
				local isValidVelocity = validVelocity(hit, v)

				if isValidVelocity and not crashed then
					if v.Name == "tire" or v.Name == "Wheel" or v.Parent.Name == "FL" or v.Parent.Name == "FR" or v.Parent.Name == "RL" or v.Parent.Name == "RR" then
						print(script.Parent.Body.PrimaryPart.AssemblyLinearVelocity.Magnitude)
						
						return
					end

					crashed = true

					crashParticles(v)
					crashSound(v)
					crashVelocity(v)

					v:BreakJoints()

					task.delay(.75, function()
						crashed = false
					end)
				end
			end

			if isValidVehicle then
				local isValidVelocity = validVelocity(hit, v)

				if isValidVelocity and not pvp then	
					pvp = true

					crashParticles(hit)
					crashSound(hit)
					crashVelocity(hit)

					hit:BreakJoints()

					task.delay(1.25, function()
						pvp = false
					end)
				end
			end
		end)
	end
end

How about trying if the part the vehicle touches has a specific value in it? And making the vehicle crash?

Try this:

local function crashParticles(part)
	if part then
		for i, particle in pairs(script:GetChildren()) do
			if particle:IsA("ParticleEmitter") then
				local newParticle = particle:Clone()
				newParticle.Enabled = false
				newParticle.Parent = part
				newParticle:Emit(6)
				debris:AddItem(newParticle, .25)
			end
		end
	else
		warn(script.Name.. " -> crashParticles Function: part argument is nil.")
	end
end

local function crashSound(part)
	if part then
		local getSounds = sounds:GetChildren()
		local randomCrashSound = getSounds[math.random(1, #getSounds)]:Clone()
		randomCrashSound.Parent = part
		randomCrashSound:Play()

		debris:AddItem(randomCrashSound, 4)
	else
		warn(script.Name.. " -> crashSound Function: part argument is nil.")
	end
end

local function crashVelocity(part)
	part.CanCollide = false
	part.Anchored = false

	local bodyVelocity = Instance.new("BodyVelocity")
	bodyVelocity.P = 250
	bodyVelocity.MaxForce = Vector3.one * 9999
	bodyVelocity.Velocity = Vector3.one * 20
	bodyVelocity.Parent = part

	debris:AddItem(bodyVelocity, .25)
end

local function validVelocity(hit, part)
	if part.Velocity.Magnitude > hit.Velocity.Magnitude + 30 or hit.Velocity.Magnitude > part.Velocity.Magnitude + 65 then
		return true
	end

	return false
end

local function validHit(hit, part)
	if hit and part then
		if hit.Parent then
			if not table.find(possibleParents, hit.Parent.Name) and not table.find(ignoreHit, hit.Name) and not table.find(ignorePart, part.Name) then
				if not hit.Parent:FindFirstChild("Humanoid") and hit.CanCollide == true and not game.Players:FindFirstChild(hit.Parent.Name) then
					if hit:IsA("Part") or hit:IsA("UnionOperation") or hit:IsA("MeshPart") or hit:IsA("WedgePart") or hit:IsA("CornerWedgePart") then
						return true
					end
				end
			end

			return false
		else
			warn(script.Name.. " -> validHit Function: hit.Parent = nil.")
		end
	else
		warn(script.Name.. " -> validHit Function: One of two arguments is nil.")
	end
end

local function validVehicle(hit)
	if hit then
		if hit.Parent then
			if table.find(insideParents, hit.Parent.Name) then
				local vehicleName = hit.Parent.Parent.Parent.Name

				if script.Parent.Name ~= vehicleName then
					return true
				end
			elseif table.find(outsideParents, hit.Parent.Name) then
				local vehicleName = hit.Parent.Parent.Name

				if script.Parent.Name ~= vehicleName then
					return true
				end
			end

			return false
		else
			warn(script.Name.. " -> validVehicle Function: hit.Parent = nil.")
		end
	else
		warn(script.Name.. " -> validVehicle Function: Hit does not exist.")
	end
end

--//Script
local PrimaryPart = script.Parent.Body.PrimaryPart

local previousMagnitude = PrimaryPart.AssemblyLinearVelocity.Magnitude
local crashSpeed = 60 --//Tweak if needed

local predictedImpact = false

local wheelNames = {
	"tire",
	"Wheel",
	"FL",
	"FR",
	"RL",
	"RR",
}

task.spawn(function()
	while task.wait(1) and PrimaryPart:IsDescendantOf(workspace) do
		local currentMagnitude = PrimaryPart.AssemblyLinearVelocity.Magnitude
		
		if previousMagnitude > currentMagnitude and previousMagnitude - currentMagnitude >= crashSpeed then
			predictedImpact = true
			
			task.delay(1, function()
				predictedImpact = false
			end)
		end
		
		previousMagnitude = currentMagnitude
	end
end)

for i, v in pairs(script.Parent:GetDescendants()) do
	if v:IsA("Part") or v:IsA("UnionOperation") or v:IsA("MeshPart") then
		v.Touched:Connect(function(hit)
			local isValidHit = validHit(hit, v)
			local isValidVehicle = validVehicle(hit)

			if isValidHit then
				local isValidVelocity = validVelocity(hit, v)

				if isValidVelocity and not crashed then
					if table.find(wheelNames, v) and not predictedImpact then
						return
					end

					crashed = true

					crashParticles(v)
					crashSound(v)
					crashVelocity(v)

					v:BreakJoints()

					task.delay(.75, function()
						crashed = false
					end)
				end
			end

			if isValidVehicle then
				local isValidVelocity = validVelocity(hit, v)

				if isValidVelocity and not pvp then	
					pvp = true

					crashParticles(hit)
					crashSound(hit)
					crashVelocity(hit)

					hit:BreakJoints()

					task.delay(1.25, function()
						pvp = false
					end)
				end
			end
		end)
	end
end

When predictedImpact is true, it breaks wheels that were touching anything. So if I crashed into one the wheels, any other wheel could of broke due to it touching the ground

Sorry for not saying this earlier, but you should just add a tag for the ground and ignore it when you’re destroying the wheels.