How do I check if a player is closer than another player to something?

I’m making an npc script, but I want to make sure the player closes to the npc is the player the npc chases. How can I do this?

Use Magnitude to check how close the player to NPC is.

local dist = 40
if (plrTorso.Position - npcTorso.Position).Magnitude < dist then
   --// ur code here
end

Read the title please, I want to be able to make it so it goes to the person nearest to it there could be more than one player in range.

I dont exact understand what you mean…

he means that, pretend you have a part, ad you want to know which player is the closest to the part

Ok,
@Dracolyx then use loop check:

function check()
	local dist = 30
	local torso
	for _,v in pairs(game.Players:GetPlayers()) do
		if v.Character and v.Character:FindFirstChild("Humanoid").Health > 0 then
			local temp = v.Character:FindFirstChild("Torso")
			if (npcTorso.Position - temp.Position).Magnitude < dist then
				torso = temp
			end
		end
	end
	return torso
end

while wait(0.3) do
	local torso = check()
	if torso then
		print('the nearest is '..torso.Parent.Name)
	end
end
1 Like

Make a dictionary {plr1 = distanceToNpc, plr2 = distanceToNpc, …}, then find the minimum value of distance and return the corresponding plr where plr is the Player instance. It can also be player’s name or whatever you want.

1 Like

Here is a script I found

local NPC = script.Parent
local Humanoid = script.Parent:FindFirstChild(“Humanoid”)
local HRP = script.Parent:FindFirstChild(“HumanoidRootPart”)

local function GetClosestPlayer(range)
    local List = {}
	local Target = nil
	for i, v in pairs(game.Players:GetPlayers()) do
		local dist = v:DistanceFromCharacter(HRP.position)
		if dist <= range then
			table.insert(List, {dist, v})
		end
	end
		
	table.sort(List, function(A, B)
		return A[1] < B[1]
	end)
	
	pcall(function()
		Target = List[1][2]
	end)
	
	return Target
end

while true do
    wait()
    local Target = getClosestPlayer(30) -- // change 30 to the max distance
    if Target == nil then return end
    Humanoid:MoveTo(Target.PrimaryPart)
    Humanoid.MoveToFinished:Wait()
end
1 Like

No, this solution isn’t good because you’re sorting the table which is unnessecary and makes the algorithm slower than it could be. The only thing you have to do with that List is to iterate over it and find the minimum value.

Average complexity:

  • With sorting O(n log n) (quick sort)
  • Without sorting O(n) (only one iteration)

Instead of that part:

table.sort(List, function(A, B)
	return A[1] < B[1]
end)
	
pcall(function()
	Target = List[1][2]
end)
	
return Target

Do simply

local minIndex = -1
local minDist = math.huge
for i,v in ipairs(List) do
    if v[0] < minDist then
        minDist = v[0]
        minIndex = i
    end
end

if minIndex ~= -1 then
    return List[minIndex][2]
else
    return nil
end
2 Likes

The answers here are a tiny bit over complicated, so I’m going to post a different, much simpler solution.
This function takes in a range (max distance to detect) and a Vector3 pos. It’ll return the closest player to the Pos within Range aswell as the distance of that player.

local function GetClosestPlayer(Range, Pos)
	local Player, Dist = nil, math.huge;
	for i, v in pairs(game:GetService'Players':GetPlayers()) do
		local newDist = v:DistanceFromCharacter(Pos);
		if (Dist <= Range and newDist < Dist and v.Character) then
			Player, Dist = v, newDist;
		end
	end
	return Player, Dist;
end

Example usage:

local Player, Dist = GetClosestPlayer(120, SomePart.Position);
-- Player = closest player, or nil if none
-- Dist = player's distance from Pos
1 Like

Actually you guys are all wrong :triumph: (Actually now I’m wrong :pensive:)
https://devforum.roblox.com/t/psa-magnitude-now-obliterates-squared-distance-checks-in-luau-with-benchmarks/959737

But in all seriousness there’s a faster way to do distance checks. Calculating distance is expensive especially since there are square roots involved which are one of the slowest operations to perform. The solution is FuzzyEq and our own version of Magnitude. FuzzyEq doesn’t square root the result internally resulting in a really large performance boost over a lot of iterations.

Modified function from @fireboltofdeath

local function DistSq(Difference) -- Function to find squared distance
	return Difference.X^2 + Difference.Y^2 + Difference.Z^2 -- Exactly the same as magnitude without the square root part which is the slowest part
end

local function GetClosestPlayer(Range, Pos)
	local Player, Dist = nil, math.huge;
	for _, player in pairs(game:GetService'Players':GetPlayers()) do
		if player.Character and player.Character:FindFirstChild("HumanoidRootPart") and player.Character:FindFirstChild("Humanoid") then -- Make sure the character exists to prevent errors
			if player.Character.Humanoid.Health > 0 then -- Make sure they're alive
				local OtherPos = player.Character:GetModelCFrame().p -- Get their position
				if OtherPos:FuzzyEq(Pos, Range) -- Player is in range
					local SqDist = DistSq(OtherPos - Pos) -- "Fuzzy" distance used above
					if SqDist < Dist then -- Check if they are closer, if so select them instead
						Player, Dist = player, SqDist; -- Save the player and distance so we can continue finding closer players.
					end
				end
			end
		end
	end
	return Player, math.sqrt(Dist); -- Finally yield the player and the distance. Note that I have not square rooted it yet so it needs to be square rooted to be considered distance.
end
4 Likes