Need help with npc pathfinding updating when player moves too far from waypoint or too close to player

I’ve been trying for hours on an AI Pathfinder on how to detect if a player has moved too far from a waypoint or if player is too close to the npc, but I still haven’t found an optimized solution.

Currently, the code below just stutters for a split second.

Main Pathfinding

local function followPlayer(targetHRP)
	while task.wait() do
		local distanceToPlayer = (npc.HumanoidRootPart.Position - targetHRP.Position).Magnitude

		if distanceToPlayer >= 18 then
			local path = getPath(targetHRP.Position)
			local waypoints = path:GetWaypoints()

			for i, waypoint in pairs(waypoints) do
				local distanceToWayPoint = (targetHRP.Position - waypoints[#waypoints].Position).Magnitude
				if distanceToWayPoint > 18 then
					break
				end

				if waypoint.Action == Enum.PathWaypointAction.Jump then
					npc.Humanoid.Jump = true
				end

				npc.Humanoid:MoveTo(waypoint.Position)
				npc.Humanoid.MoveToFinished:Wait()
			end
		else
			hmd:MoveTo(targetHRP.Position)
		end
	end
end

local function pathFindTo(destination, player)
	local target = findTarget(player)

	if target and target.Humanoid.Health > 0 then
		local targetHRP = target:WaitForChild("HumanoidRootPart")

		coroutine.wrap(followPlayer(targetHRP))()
	end
end

How the function is played

    humanoid.Died:Connect(function()
		check = false
	end)
	
	while task.wait() do
		if (check) then
			if character and character:FindFirstChild("HumanoidRootPart") then
				local target = findTarget(player)
					
				if target then
					pathFindTo(target:WaitForChild("HumanoidRootPart").Position, player)
				end
			end
		end
	end

basically the solutions to the problems I want to find:

  • Detect if a player is too close to npc or too far from waypoint, then break the path (even if its on :Wait() ) and redo the findPath function.

and that’s all. If someone could help, I would be very glad as I am awake at 4 am agonizing what’s wrong.

2 Likes
local follow = true

local function followPlayer(targetHRP)
	while task.wait() do
		local distanceToPlayer = (npc.HumanoidRootPart.Position - targetHRP.Position).Magnitude

		if distanceToPlayer >= 18 then
			local path = getPath(targetHRP.Position)
			local waypoints = path:GetWaypoints()

			for i, waypoint in pairs(waypoints) do
				local distanceToWayPoint = (targetHRP.Position - waypoints[#waypoints].Position).Magnitude

				if distanceToWayPoint > 18 then
					print("HI")
					break
				end

				if waypoint.Action == Enum.PathWaypointAction.Jump then
					npc.Humanoid.Jump = true
				end

				npc.Humanoid:MoveTo(waypoint.Position)
				npc.Humanoid.MoveToFinished:Wait()
			end
		else
			hmd:MoveTo(targetHRP.Position)
		end
	end
end

local function pathFindTo(destination, player)
	local target = findTarget(player)

	if target and target.Humanoid.Health > 0 then
		local targetHRP = target:WaitForChild("HumanoidRootPart")
		
		follow = false
		task.wait()

		follow = true
		coroutine.wrap(function() followPlayer(targetHRP) end)()
	end
end

this kind of works for detecting player movement while ignoring the wait function in the loop. But way too many threads open. Anyone know how to limit the amount of threads?

my best work for now,

local maxThreads = 30
local activeThreads = 0

local isMoving = true
local lock = false
local ifPath = false

local secondLock = false
local waitForHumanoid = nil

local function followPlayer(targetHRP)
	local distanceToPlayer = (npc.HumanoidRootPart.Position - targetHRP.Position).Magnitude
	
	if distanceToPlayer >= 9 then		
		if (targetHRP.Position - vectorValue.Value).Magnitude > 7 and lock and not secondLock and ifPath then
			ifPath = false
			
			lock = false
			
			secondLock = true
		elseif lock == false then
			activeThreads += 1
			
			lock = true
			
			local waypoints = {}

			if ifPath == false then
				ifPath = true
				local path = getPath(targetHRP.Position)
				waypoints = path:GetWaypoints()
			end
			
			for i, waypoint in pairs(waypoints) do		
				if activeThreads > 1 then
					break
				end
				
				if waypoint.Action == Enum.PathWaypointAction.Jump then
					npc.Humanoid.Jump = true
				end

				vectorValue.Value = waypoints[#waypoints].Position
				
				secondValue = vectorValue.Value

				npc.Humanoid:MoveTo(waypoint.Position)

				npc.Humanoid.MoveToFinished:Wait()
				
				if secondLock then
					break
				end
			end
			
			if secondLock then
				secondLock = false
				lock = true
			end
			
			activeThreads -= 1
		end
	else
		isMoving = true
        secondLock = true

		while isMoving do
			npc.Humanoid:MoveTo(targetHRP.Position)

			task.wait()

			if (npc.HumanoidRootPart.Position - targetHRP.Position).Magnitude > 9 then
				isMoving = false
			end
		end

	end
end

local function pathFindTo(destination, player)
	local target = findTarget(player)

	if target then
		local targetHRP = target:WaitForChild("HumanoidRootPart")

		while true and task.wait() do
			if target.Humanoid.Health > 0 then	

				followPlayer(targetHRP)
			end
		end
	end
	
	print(target)
end

local function createThreads(target, player)
	for i = 1, maxThreads do
		coroutine.wrap(function() pathFindTo(target:WaitForChild("HumanoidRootPart").Position, player) end)()

		task.wait(0.1)
	end
end
1 Like

Put another check within that for loop of the waypoints to check how far the player is from the NPC like you did with distancetowaypoint, if it’s too far then break.

Once it breaks out the for loop it’ll restart so that’s fine.