NPC not following nearest player

Hi there, I’m currently making an NPC that follows the nearest players. (Have no experiences in AIs, pardon me for any mistakes in the code). Basically the current code I have is very simple, you can have a look at it here:
AIClass:

local AIClass = {}
AIClass.__index = AIClass


local pathFinding = require(script.PathFinding)

function AIClass.init(AI, range)
	local self = setmetatable({}, AIClass)
	
	self.Target = nil
	self.distToTarget = range
	self.detectionRange = range
	self.AI = AI

	self.detectionBox = pathFinding:CreateDetection(self.AI, self.detectionRange)
	
	return self
end

function AIClass:findTarget()
	local getParts = workspace:FindPartsInRegion3WithIgnoreList(self.detectionBox, {self.AI})
	
	for _, v in pairs(getParts) do
		if v.Parent:FindFirstChild("Humanoid") then
			if self.Target ~= v.Parent and self.Target ~= nil then
				if (self.AI.HumanoidRootPart.Position - v.Parent.HumanoidRootPart.Position).Magnitude < (self.Target.HumanoidRootPart.Position - v.Parent.HumanoidRootPart.Position).Magnitude then
					pathFinding:ComputePath(self.AI, v.Parent.HumanoidRootPart.Position)
				end
			else
				pathFinding:ComputePath(self.AI, v.Parent.HumanoidRootPart.Position)
			end
			
			self.Target = v.Parent
			self.distToTarget = (self.AI.HumanoidRootPart.Position - self.Target.HumanoidRootPart.Position).Magnitude
		end
	end
	
	return self.Target
end

return AIClass

Path finding module:

local PathFinding = {}

local PathFindingService = game:GetService("PathfindingService")

local region

function PathFinding:CreateDetection(AI, size)
	-- create part with all the infos blah blah blah
	region = Region3.new(part.Position - (0.5 * part.Size), part.Position + (0.5 * part.Size))

	return region
end

function PathFinding:ComputePath(AI, destination)
	local AIHead = AI.Head
	local AIHum = AI.Humanoid
	local AIHrp = AI.HumanoidRootPart

	local raycastParams = RaycastParams.new()
	raycastParams.FilterDescendantsInstances = {AI}
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	
	if AIHead then
		local hit = workspace:Raycast(AIHead.Position, (destination - AIHead.Position) * 100, raycastParams)

		if hit then
			if hit.Instance.Parent:FindFirstChild("Humanoid") then
				AIHum:MoveTo(destination)

			else
				local path = PathFindingService:CreatePath()
				path:ComputeAsync(AIHrp.Position, destination)
				
				if path.Status == Enum.PathStatus.Success then
					local points = path:GetWaypoints()
					for i, v in pairs(points) do
						AIHum:MoveTo(v.Position)

						if v.Action == Enum.PathWaypointAction.Jump then
							AIHum.Jump = true
						end
					end				
				else
					AIHum:MoveTo(destination)
				end
			end
		end
	end
end

return PathFinding

You can have a look at the issue here: https://gyazo.com/7462a870c6b5ce1fb6b7531568b33ac8
Even though it seems fine, some errors started to occur, it will follow a wrong player even though a player is already in front of them (You can have a look at the output for the current target) . I have tried adding a break / return whenever it finds a closer target than its’ current one, but it will break the code because the AI will now have 2 target to follow for whatever reason.
Any help is appreciated!
Edit: pls help i have no idea why it’s functioning like this

Would you consider switching from a part to something more performant like a table or CollectionService for handling the characters that are available? Doing that would make this simpler, I think what’s happening is that your AI is iterating and finding the other character and calculating a path for it, which is asynchronous, which is why it keeps going back to 1.

You should make 3 changes:
1- make a table with the available characters’ models, this would clean up you looking for _.Parent.Humanoid and would avoid you iterating through the characters too many times.
2- use a loop to determine the closest humanoid before calculating a new path.
3- switch from a part and iterate through the characters using .Magnitude instead

I don’t know if that makes sense but:

local maxCharacterRadius = 25 -- let's say the character must be within 25 studs

-- ...

local characters = table.of.models

local smallestDistance, smallestDistanceCharacter = math.huge, nil -- these will be how we will navigate finding the closest character
for i,v in ipairs(characters) do
    local humanoidRootPart = v:FindFirstChild('HumanoidRootPart')
    if not humanoidRootPart then continue end -- character probably isn't valid
    local humanoid = v:FindFirstChild('Humanoid')
    local currentMagnitude = (AIHrp.Position - humanoidRootPart.Position).Magnitude
    if (currentMagnitude < smallestDistance) and (currentMagnitude < maxCharacterRadius) then -- if it's smaller than the current smallest distance and it's in range then
        smallestDistance, smallestDistanceCharacter = currentMagnitude, v
    end
end
if smallestDistanceCharacter then
    -- this is the smallest character, chase the new smallest character
else
    -- nobody's in range
end
1 Like