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
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.
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
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
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
Actually you guys are all wrong (Actually now I’m wrong )
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