Using Player:DistanceFromCharacter() in place of TouchEnded

As all of you probably know, the TouchEnded event is highly unreliable and often registers whilst the player would be “Inside” of a part. First, I was using Pythagoras’s theorem to work out the magnitude of the position of the player and then the part, subtracting them to get the distance, checking if it was negative (if so, multiply by -1 to make it positive). However, the distance for this wasn’t working very well:
image

The yellow represents the part, whereas the black squares represent the positions the player would stand. If the player stood on the position of the black square, the distance would (roughly) be equal to the number. Standing between the squares would give numbers equal to the appropriate distance between the two squares +/- the squares value. While the squares over-all size was 30, half of 30 is 15, meaning that if you stood in certain corners of the square, it wouldn’t register you as being on the square, likewise with in other areas, allowing you to be off the square as well as the script registering you as on the square.

Therefore, I swapped to Player:DistanceFromCharacter(). This time, all side centres (values of 10) would be equal to 15 (as wanted), and all corners would be equal to values of 20. This, once again, would make it so that you wouldn’t be registered as on the square if you were near the corners. What would a potential fix/check for this be?

(Part.Position - character.HumanoidRootPart.Position).magnitude

While that solved the magnitude bug previously of displaying 0’s in 2 corners - it gives the same value as the Player:DistanceFromCharacter() function.

It’s supposed to do so. Player:DistanceFromCharacter() is just a function doing literally the same thing.

I know, I’m asking if there are any ways to make it so you can use this method, or another method, to try and find out whether a player is on a part, because corners will be cast as a larger distance from the centre than the side to the centre.

Finally done with this horror.

local part = workspace.Part

local char = workspace:WaitForChild("nooneisback") --been to lazy to fetch the character properly
local hrp = char:WaitForChild("HumanoidRootPart")

local size = part.Size
	local sizex,sizey,sizez = size.X/2,size.Y/2,size.Z/2
	local sizemin = math.min(sizex,sizey,sizez)
	

game:GetService("RunService").Heartbeat:Connect(function()
	local charpos = hrp.Position
	
	local cf = part.CFrame
	local pos = cf.Position
	local mat3 = cf-pos

	local diff = mat3*(charpos-pos)
	
	if diff.magnitude <= size.magnitude then
		local touching = false
		if diff.magnitude<=sizemin then
			touching = true
		else
			do
				local dot = math.abs(mat3.RightVector:Dot(diff))
				if dot<=sizex then
					local dot = math.abs(mat3.UpVector:Dot(diff))
					if dot<=sizey then
						local dot = math.abs(mat3.LookVector:Dot(diff))
						if dot<=sizez then
							touching = true
						end
					end
				end
			end
		end
		print((touching and "Touching") or "Not touching")
	end
end)

Note that it can only detect whether the RootPart’s position is inside the part, but not if any part of the character is, making that happen would render it too inefficient.

5 Likes

Aye - it works perfectly. The requirements were preferred anyway, this way people wont spam the script by standing by the edge and rotating.

Would have preferred explanations, but you have my gratitude nonetheless (plus, it seems like most of it is would just mathematical explanations)

Thank you.

1 Like

Basically, the script takes the part’s CFrame every frame. It subtracts the character’s position from the part’s position and the transforms it by the rotation matrix. This is actually the same as cf:PointToObjectSpace, but I like writing the full definition of functions not to make any errors.

CFrames are just weirdly written 4x4 transformation matrices, so subtracting the position vector from them gives you a 3x3 rotation matrix extended to a 4x4 matrix, but the position values are all 0 so it still acts like a 3x3.

Next we have to check if the part is within the bounds. There is no reason to run the check if the part is withing the smallest size value. With that out of the way, we have to check for each face if the distance on an imaginary axis line from the part’s center is within the size of that axis.

That is done by obtaining a dot product of the direction of the face and the transformed character’s position. We are basically moving the character’s position to the closest point on the axis line and checking whether it’s within the size constraint.

3 Likes

Thanks for the explanation. :slight_smile:

1 Like