# How do I get 'Outside Distance' between two parts?

1. What do you want to achieve?
I have a code that compares the distance of two objects by subtracting their positions and getting the magnitude.

2. What is the issue?
This works well except that you have to get really close to an object if their size is relatively big :

• The red sphere indicates the range of the turret
• The blue dot // pivot point indicates the point from where the range is being calculated
1. What solutions have you tried so far?
For now, I subtract the âraw distanceâ of the two objects with the radius:
``````function module.distanceBetween(self:BasePart, target: BasePart): number
local s1 = self.Size
local s2 = target.Size
local radius1 = math.sqrt((s1.X/2)^2 + (s1.Z/2)^2)
local radius2 = math.sqrt((s2.X/2)^2 + (s2.Z/2)^2)
local diff = self.Position - target.Position
-- radius -> center to any edge
end
``````

This would work well except for objects that are much longer on one axis; For example a wall:

• The turret can shoot the Repair Bay now, Yay!

• Somehow it can shoot a wall outside its range???

• The intersection between green (object radius) and red (weapon range) shows that the turret can shoot the wall. (Since we now subtract the object radius from the distance to get the final distance)

• This gives the impression that the turret can shoot much farther than the range implied by the red circle

1. Goals
2 Likes

Assuming that both the origin and target part has the same X and Z size values, you can use this.

`return (origin.Position - target.Position).Magnitude - origin.Size.X/2 - target.Size.X/2`

In your scenario, you can use the red/green cylinders as your target and origin parts. You might have to switch the X to Y or Z, this is because cylinders lay down flat on default

2 Likes

Thatâs because the script isnât accounting for if the object itself is inside the radius, itâs only checking to see if the other objectâs radiusâ are overlapping with the turretâs radius.

I suggest you use Raycasting to see if an object is within the ray of the turret.

``````function module.castRay(turret)
local turretSize = turret.Size
local turretPosition = turret.Position
local turretDirection = math.sqrt((s1.X/2)^2 + (s1.Z/2)^2)

local Ray = Ray.new(turretPosition, turretDirection)

local hit, position = workspace:FindPartOnRay(Ray, turret)
end
``````

This method will probably require more checks for things like ensuring that the turret isnât shooting the floor or itself, but itâs the method that games usually use for things like this. However, if @JonYawnsâ way works efficiently enough for you then use that instead!

Oh!
I have thought of using raycasting before, but I wouldnât want 50+ units raycasting to everyone else every 0.5 seconds just to find the nearest target, but reading your reply made me realise, I just have to raycast to the nearest one it can find â

``````function module.GetTarget(origin: Vector3)
local nearest = module.getClosestTarget(origin) -- previous distance comparison function
if nearest == nil then return nil end

local param = RaycastParams.new()
param.FilterDescendantsInstances = {map, nearest}
param.FilterType = Enum.RaycastFilterType.Whitelist
local ray = workspace:Raycast(origin, diff.Unit * range, param)
return (ray and ray.Instance:IsDescendantOf(nearest) and nearest) or (ray == nil and nil)
end)
``````

But this runs into another problem:
Since the distance comparison function returns the closest target, it wonât change the target if the ray doesnât hitâŚ leading to it forever trying to hit a wall even when a smaller object is closer than the wall

1 Like

Thatâs when the problem Iâm trying to solve happens, when the X and Z size values are not the same.

TheSuzerain below gave me insight to solve it, just letting you know

Edit:

Ok I solved the part where the âtrying to get to same target foreverâ problem by:

1. Get all the nearest targets
2. Sort the nearest targets from closest to farthest
3. Repeat raycast check until a valid target is found
``````function module.GetTarget(self:BasePart, origin: Vector3)
module.checkParam = module.checkParam or RaycastParams.new()
local param = module.checkParam

local nearby = module.GetNearbyTargets(origin, range, function(part, diff)
if part == self then return false end
return true
end)

table.sort(nearby, function(a: BasePart,b: BasePart) -- Sort the table from closest to farthest
local diffA = (a.Position - origin)
local diffB = (b.Position - origin)
return Vector.SquaredMagnitude(diffA) < Vector.SquaredMagnitude(diffB)
end)

local target = nil
param.FilterDescendantsInstances = {self, self.Parent}
param.FilterType = Enum.RaycastFilterType.Blacklist
while target == nil and #nearby > 0 do
local nextTarget = table.remove(nearby, 1)
local ray = workspace:Raycast(origin, diff.Unit*range, param)
target = (ray and getUnitFromPart(ray.Instance)) or nil
end
return target
end
``````
1 Like