Finding Closest NPC Function

So, the code down below is supposed to check nearby NPCs, every physics update, to see if they are:

  • Within the DETECTION_RANGE
  • And to also find out which NPC is the closest to the player

It works as intended, however I can’t help but feel like this is a very inefficient method of doing this. Not only that, but this script seems to create a significant frame drop, when run on slower devices, which is not what I want. Would anyone be able to give suggestions on improving the structure of this script, or anything that will improve the performance of it?

local DETECTION_RANGE = 10

local player = game:GetService("Players").LocalPlayer
local char = player.Character or player.CharacterAdded:Wait()

local NPCFolder = workspace:WaitForChild("DialogueNPCs")

local NPCInRange = nil

local function FindClosestNPC()
	local inRangeNPCs = {}
	
	for _, NPC in pairs(NPCFolder:GetChildren()) do
		if (char.PrimaryPart.Position - NPC.PrimaryPart.Position).Magnitude <= DETECTION_RANGE then
			table.insert(inRangeNPCs, NPC)
		end
	end
	
	local closestNPC = inRangeNPCs[1]
	for i = 2, #inRangeNPCs do
		local currentNPC = inRangeNPCs[i]
		
		if (char.PrimaryPart.Position - currentNPC.PrimaryPart.Position).Magnitude < (char.PrimaryPart.Position - closestNPC.PrimaryPart.Position).Magnitude then
			closestNPC = currentNPC
		end
	end
	
	NPCInRange = closestNPC
end


game:GetService("RunService").Heartbeat:Connect(function()
	FindClosestNPC()
end)

I would recommend to just return the closestNPC rather than overwriting a variable. This code works but you do not have to use a placeholder variable for NPCInRange in this case.

This code is okay. You can also use table.sort here.

local npcDistances = {}
for _, _npc in pairs(NPCFolder:GetChildren()) do
    local _distance = char.PrimaryPart.Position - _npc.PrimaryPart.Position).Magnitude
	if (_distance <= DETECTION_RANGE then
		table.insert(npcDistances, {
            npc = _npc,
            distance = _distance,
        }
	end
end

table.sort(npcDistances, function(a, b)
    return a.distance < b.distance
end)

return npcDistances[1].npc
1 Like

Damn, I wasn’t aware of that. Thanks for your help!