Script making CanCollide false part work differently?

I have a CanCollide false part covering the spawn area in my game, and without the script enabled I can spawn inside no issues, but with the script enabled I spawn on the roof. The script, as seen below, has a Touched event which I thought was the issue. I tried spawning in without the TouchInterest that the Touched event creates and still spawned on the roof. If anyone could help or explain why this happens I would appreciate it.

Script inside the part:

local parent = script.Parent

parent.Touched:Connect(function(part)
	if part.Parent:FindFirstChild("Humanoid") then
		if part == part.Parent.PrimaryPart then
			Instance.new("ForceField", part.Parent)
		end
	end
end)

parent.TouchEnded:Connect(function(part)
	if part.Parent:FindFirstChild("Humanoid") then
		if part == part.Parent.PrimaryPart then
			part.Parent:FindFirstChild("ForceField"):Destroy()
		end
	end
end)

Video:

1 Like

Add a wait() function at the start of your function. This might resolve it. 1 or 2 seconds can be enough.

Just tried and it works when I first press play, but when I reset I still spawn on the roof. Very weird.

Add a if statement to both your functions to check if the player already has a forcefield. Whenever the player moves inside of that part, the Touched event will be fired, so your script will create a lof of force fields. I’m not sure if this will fix the second issue that you just pointed out.

local parent = script.Parent

parent.Touched:Connect(function(part)
	if part.Parent:FindFirstChild("Humanoid") and part ~= nil then -- Check if the part exists and if it's a humanoid character
		if part == part.Parent.PrimaryPart then
			if not part.Parent:FindFirstChildOfClass("ForceField") then -- If the player has not a forcefield yet...
				local forceField = Instance.new("ForceField", part.Parent) -- Create a forcefield
			end
		end
	end
end)

parent.TouchEnded:Connect(function(part)
	if part.Parent:FindFirstChild("Humanoid") and part ~= nil then -- If is a humanoid character and the part exists, then...
		if part == part.Parent.PrimaryPart then
			if part.Parent:FindFirstChildOfClass("ForceField") then -- If the character has a forcefield...
				part.Parent:FindFirstChild("ForceField"):Destroy() -- Remove the forcefield
			end
		end
	end
end)

That’s not the case because it only fires if the HumanoidRootPart touches the part (if part == part.Parent.PrimaryPart then). That’s what I thought at first but it only fires once after testing.

Then I have no idea of how to fix this. But on my game, I had a part that covered an entire area of the game, anchored and with CanCollide set to false, and the players sometimes spawned on the roof, and sometimes on the ground, no scripts were inside of that part and it was only used to detect how many players are in that region and do a specific action with them, but stills not creating any instances on the player character.
After I removed this part and created a different system, this problem was gone.

I suggest creating two parts: one part on the player spawn (which the player will always touch when they spawn), with one script inside of it to create the force field. Then create another part in the end of the safe zone, that when the player touches, removes the force field. This worked for me, it was happening just because that the part was there and filling that area.

Alright so I just tested everything in multiple situations. My conclusion is that it is on Roblox’s side. Whenever a script uses the Touched function on a part that has CanCollide off and you try to spawn inside it, Roblox seems to view the part as if CanCollide is on.

local parent = script.Parent
parent.Touched:Connect(function(part)
 wait(5)
  print("test")
end)

Even this will cause you to spawn on the top. Might be a bug, because I assume none of this was intended to be this way.

1 Like

I doubt it will get fixed because I don’t think Touched is used very often. I might try :GetTouchingParts() instead.

If you want a player to have a forcefield within spawn area, you can do a distance check from the spawn part and if they are within range, give them a forcefield if they don’t have one.

This will be way more performant than using .Touched which will fire a lot more.

The event only fires once per player though, plus using that method will need a loop

The event will not fire once person. ANY part that touches it of the player will make the event fire.

but it wont get past the first if statement if it doesnt belong to a player

Actually, it will detect any humanoid entity that touches the part. If you want to detect only players, do:

if game.Players:FindFirstChild(part.Parent.Name) and part.Parent:FindFirstChild('Humanoid') then

It doesn’t matter if it doesn’t pass the first if statement, it’s still being fired every time a part touches it which might cause lag with 10+ players and dozens of parts per player at spawn firing the event.