How to find the distance between 2 parts

I’m trying to calculate the distance between 2 parts, but I don’t want to use their position, it’s hard to get what I mean so I drew something:


I would like to calculate the purple line, is there any way I can do that?

1 Like

You could try something like this, takes the position and clamps to the part 2, i think this is a right function, though raycasting might work

local function getClosestDistance(part1, part2)
	-- Get closest point on part2's surface from part1's center
	local closestPoint = part2.CFrame:PointToObjectSpace(part1.Position)
	local halfSize = part2.Size / 2
	
	-- Clamp to part2's bounds
	closestPoint = Vector3.new(
		math.clamp(closestPoint.X, -halfSize.X, halfSize.X),
		math.clamp(closestPoint.Y, -halfSize.Y, halfSize.Y),
		math.clamp(closestPoint.Z, -halfSize.Z, halfSize.Z)
	)
	
	-- Convert back to world space
	closestPoint = part2.CFrame:PointToWorldSpace(closestPoint)
	
	-- Distance from part1's closest surface point to that point
	local part1Closest = part1.CFrame:PointToObjectSpace(closestPoint)
	local part1HalfSize = part1.Size / 2
	
	part1Closest = Vector3.new(
		math.clamp(part1Closest.X, -part1HalfSize.X, part1HalfSize.X),
		math.clamp(part1Closest.Y, -part1HalfSize.Y, part1HalfSize.Y),
		math.clamp(part1Closest.Z, -part1HalfSize.Z, part1HalfSize.Z)
	)
	
	part1Closest = part1.CFrame:PointToWorldSpace(part1Closest)
	
	return (part1Closest - closestPoint).Magnitude
end

2 Likes

i just made a simple example for you. this is how i would get the distance between corners. (this example is very simple. u should use a loop to calculate all corners if that is ur intention)

code:

local Part1 = workspace.Part1
local Part2 = workspace.Part2

local function getHalfSize(part)
	return part.Size.X / 2, part.Size.Y / 2, part.Size.Z / 2
end

local HalfX1, HalfY1, HalfZ1 = getHalfSize(Part1)
local HalfX2, HalfY2, HalfZ2 = getHalfSize(Part2)

local PartCorner1 = Part1.CFrame * CFrame.new(HalfX1, HalfY1, HalfZ1)
local PartCorner2 = Part2.CFrame * CFrame.new(-HalfX2, HalfY2, HalfZ2)

local Corners = {
	PartCorner1.Position,
	PartCorner2.Position
}

local cornerDistance = (Corners[1] - Corners[2]).Magnitude

for _, corner in ipairs(Corners) do
	local referencePart = Instance.new("Part")
	referencePart.Anchored = true
	referencePart.BrickColor = BrickColor.random()
	referencePart.Transparency = 0.5
	referencePart.Size = Vector3.new(1, 1, 1)
	referencePart.Position = corner
	referencePart.Parent = workspace
end

print("Distance between corners: " .. cornerDistance)

place file:
DistanceBetweenCorners.rbxl (74.4 KB)

2 Likes

Also have a script for getting corners, but I think my earilier one is better because it covers edges, this one just gets every corner/vertice and compares.

local function getVertices(part)
	local cf = part.CFrame
	local size = part.Size / 2
	
	return {
		cf:PointToWorldSpace(Vector3.new(-size.X, -size.Y, -size.Z)),
		cf:PointToWorldSpace(Vector3.new(-size.X, -size.Y,  size.Z)),
		cf:PointToWorldSpace(Vector3.new(-size.X,  size.Y, -size.Z)),
		cf:PointToWorldSpace(Vector3.new(-size.X,  size.Y,  size.Z)),
		cf:PointToWorldSpace(Vector3.new( size.X, -size.Y, -size.Z)),
		cf:PointToWorldSpace(Vector3.new( size.X, -size.Y,  size.Z)),
		cf:PointToWorldSpace(Vector3.new( size.X,  size.Y, -size.Z)),
		cf:PointToWorldSpace(Vector3.new( size.X,  size.Y,  size.Z)),
	}
end

local function closestPointOnPart(point, part)
	local localPoint = part.CFrame:PointToObjectSpace(point)
	local halfSize = part.Size / 2
	
	localPoint = Vector3.new(
		math.clamp(localPoint.X, -halfSize.X, halfSize.X),
		math.clamp(localPoint.Y, -halfSize.Y, halfSize.Y),
		math.clamp(localPoint.Z, -halfSize.Z, halfSize.Z)
	)
	
	return part.CFrame:PointToWorldSpace(localPoint)
end

local function getMinDistanceBetweenParts(part1, part2)
	local vertices1 = getVertices(part1)
	local vertices2 = getVertices(part2)
	local minDistance = math.huge
	
	-- Check each vertex of part1 to closest point on part2
	for _, vertex in ipairs(vertices1) do
		local closest = closestPointOnPart(vertex, part2)
		local distance = (vertex - closest).Magnitude
		minDistance = math.min(minDistance, distance)
	end
	
	-- Check each vertex of part2 to closest point on part1
	for _, vertex in ipairs(vertices2) do
		local closest = closestPointOnPart(vertex, part1)
		local distance = (vertex - closest).Magnitude
		minDistance = math.min(minDistance, distance)
	end
	
	return minDistance
end
2 Likes

Pretty hard to beat that one without going all direct.

function getMinDistanceBetweenParts(p1,p2)
	local cf1,s1=p1.CFrame,p1.Size*0.5
	local cf2,s2=p2.CFrame,p2.Size*0.5
	local v1={
		Vector3.new(-s1.X,-s1.Y,-s1.Z),Vector3.new(-s1.X,-s1.Y,s1.Z),
		Vector3.new(-s1.X,s1.Y,-s1.Z),Vector3.new(-s1.X,s1.Y,s1.Z),
		Vector3.new(s1.X,-s1.Y,-s1.Z),Vector3.new(s1.X,-s1.Y,s1.Z),
		Vector3.new(s1.X,s1.Y,-s1.Z),Vector3.new(s1.X,s1.Y,s1.Z)
	}
	local v2={
		Vector3.new(-s2.X,-s2.Y,-s2.Z),Vector3.new(-s2.X,-s2.Y,s2.Z),
		Vector3.new(-s2.X,s2.Y,-s2.Z),Vector3.new(-s2.X,s2.Y,s2.Z),
		Vector3.new(s2.X,-s2.Y,-s2.Z),Vector3.new(s2.X,-s2.Y,s2.Z),
		Vector3.new(s2.X,s2.Y,-s2.Z),Vector3.new(s2.X,s2.Y,s2.Z)
	}
	local min=math.huge
	for i=1,8 do
		local w1=cf1:PointToWorldSpace(v1[i])
		local l2=cf2:PointToObjectSpace(w1)
		l2=Vector3.new(math.clamp(l2.X,-s2.X,s2.X),math.clamp(l2.Y,
			-s2.Y,s2.Y),math.clamp(l2.Z,-s2.Z,s2.Z))
		local c2=cf2:PointToWorldSpace(l2)
		min=math.min(min,(w1-c2).Magnitude)
	end
	for i=1,8 do
		local w2=cf2:PointToWorldSpace(v2[i])
		local l1=cf1:PointToObjectSpace(w2)
		l1=Vector3.new(math.clamp(l1.X,-s1.X,s1.X),math.clamp(l1.Y,
			-s1.Y,s1.Y),math.clamp(l1.Z,-s1.Z,s1.Z))
		local c1=cf1:PointToWorldSpace(l1)
		min=math.min(min,(w2-c1).Magnitude)
	end
	return min
end

Bam take this:

local function getClosestDistanceOptimized(part1, part2)
	local function closestPointOnPart(point, part)
		local localPoint = part.CFrame:PointToObjectSpace(point)
		local halfSize = part.Size / 2
		
		localPoint = Vector3.new(
			math.clamp(localPoint.X, -halfSize.X, halfSize.X),
			math.clamp(localPoint.Y, -halfSize.Y, halfSize.Y),
			math.clamp(localPoint.Z, -halfSize.Z, halfSize.Z)
		)
		
		return part.CFrame:PointToWorldSpace(localPoint)
	end
	
	local function getVertices(part)
		local cf = part.CFrame
		local size = part.Size / 2
		
		return {
			cf:PointToWorldSpace(Vector3.new(-size.X, -size.Y, -size.Z)),
			cf:PointToWorldSpace(Vector3.new(-size.X, -size.Y,  size.Z)),
			cf:PointToWorldSpace(Vector3.new(-size.X,  size.Y, -size.Z)),
			cf:PointToWorldSpace(Vector3.new(-size.X,  size.Y,  size.Z)),
			cf:PointToWorldSpace(Vector3.new( size.X, -size.Y, -size.Z)),
			cf:PointToWorldSpace(Vector3.new( size.X, -size.Y,  size.Z)),
			cf:PointToWorldSpace(Vector3.new( size.X,  size.Y, -size.Z)),
			cf:PointToWorldSpace(Vector3.new( size.X,  size.Y,  size.Z)),
		}
	end
	
	-- Quick check: if parts are far apart, use center approximation
	local centerDist = (part1.Position - part2.Position).Magnitude
	local maxDiagonal = (part1.Size.Magnitude + part2.Size.Magnitude) / 2
	
	if centerDist > maxDiagonal * 2 then
		-- Parts are far apart, use fast approximation
		return math.max(0, centerDist - maxDiagonal)
	end
	
	-- Parts are close, use accurate calculation
	local minDistance = math.huge
	
	local vertices1 = getVertices(part1)
	for _, vertex in ipairs(vertices1) do
		local closestPoint = closestPointOnPart(vertex, part2)
		local distance = (vertex - closestPoint).Magnitude
		minDistance = math.min(minDistance, distance)
	end
	
	local vertices2 = getVertices(part2)
	for _, vertex in ipairs(vertices2) do
		local closestPoint = closestPointOnPart(vertex, part1)
		local distance = (vertex - closestPoint).Magnitude
		minDistance = math.min(minDistance, distance)
	end
	
	return minDistance
end
2 Likes

What about simply using

BasePart:GetClosestPointOnSurface(Vector3)
local function getDistance(p1: BasePart, p2: BasePart): number
	local pos1 = p1:GetClosestPointOnSurface(p2.Position)
	local pos2 = p2:GetClosestPointOnSurface(p1.Position)
	return (pos2-pos1).Magnitude
end

game:GetService("RunService").Heartbeat:Connect(function()
	print(getDistance(workspace.part1, workspace.part2))
end)

5 Likes

This is why I come here.. what a crazy way to do this. Used both.. genius.
Now I want to try again..

function getTrueClosestDistance(p1, p2, iterations)
	iterations = iterations or 5
	local pos1 = p1.Position
	local pos2 = p2.Position
	
	for i = 1, iterations do
		pos1 = p1:GetClosestPointOnSurface(pos2)
		pos2 = p2:GetClosestPointOnSurface(pos1)
	end
	
	return (pos2 - pos1).Magnitude
end

game:GetService("RunService").Heartbeat:Connect(function()
	print(getTrueClosestDistance(workspace.part1, workspace.part2))
end)
1 Like

Eh, who even uses scripts these days? You got go in style

local module = {}

function module.GetDistance(p1: BasePart, p2: BasePart): number
	local pos1 = p1:GetClosestPointOnSurface(p2.Position)
	local pos2 = p2:GetClosestPointOnSurface(p1.Position)
	return (pos2-pos1).Magnitude
end


return module

Boom, Boom, Boom. It’s a module script.

1 Like

I see you also changed up on the spot .. :rofl:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.