Help Needed with Dynamic Pathfinding in NPC Script

Hello Roblox Developers,

I hope you’re all doing well. I am currently working on a project involving NPC pathfinding in Roblox, and I’ve encountered a challenge that I could use some help with.

I am facing difficulties with dynamically updating the pathfinding for an NPC as the player moves. The current implementation only recalculates the path when the NPC reaches its destination, resulting in a large delay before the NPC starts pathfinding to the player’s updated position.

Short video of the problem:

Here is all of my code, just one script! You can place it inside of a normal rig to test it.

local players = game:GetService("Players")

local npc = script.Parent
local Humanoid = npc:WaitForChild("Humanoid")
local npcHumanoidRootPart = npc:WaitForChild("HumanoidRootPart")

local PathfindingService = game:GetService("PathfindingService")

npcHumanoidRootPart:SetNetworkOwner(nil)

local nearestPlayer = nil
local minDistance = nil
local pathfinderPosition = nil

local path = nil
local goal = nil
local target = nil
local waypoints = nil
local folder = nil
local targetPosition = nil
local visualize = true

if visualize then
	folder = Instance.new("Folder")
	folder.Name = "Waypoints"
	folder.Parent = workspace
end

local function FindNearestPlayer()
	nearestPlayer = nil
	minDistance = math.huge
	pathfinderPosition = npcHumanoidRootPart.Position

	for _, player in ipairs(players:GetPlayers()) do
		local character = player.Character

		if character and character:FindFirstChildOfClass("Humanoid") and character:FindFirstChildOfClass("Humanoid").Health > 0 then
			local distance = (character.HumanoidRootPart.Position - pathfinderPosition).magnitude

			if distance < minDistance then
				nearestPlayer = player
				minDistance = distance
			end
		end
	end

	return nearestPlayer
end

local function getPath(destination)
	local path = PathfindingService:CreatePath()
	path:ComputeAsync(npc.HumanoidRootPart.Position, destination)
	return path
end

local function visualizeWaypoints(waypoints)
	for i, child in ipairs(folder:GetChildren()) do
		child:Destroy()
	end

	for i, waypoint in ipairs(waypoints) do
		local part = Instance.new("Part")
		part.Shape = Enum.PartType.Ball
		part.Color = Color3.fromRGB(98, 87, 255)
		part.Material = Enum.Material.Neon
		part.CFrame = CFrame.new(waypoint.Position)
		part.Name = i
		part.Anchored = true
		part.Size = Vector3.new(1, 1, 1)
		part.CanCollide = false
		part.Parent = folder
	end
end

local function pathFindTo(destination, goal)
	if destination ~= targetPosition then
		targetPosition = destination
		target = goal.Character

		if waypoints then
			table.clear(waypoints)
		end

		if target and target.Humanoid.Health > 0 then
			path = getPath(destination)
			waypoints = path:GetWaypoints()

			if folder then
				visualizeWaypoints(waypoints)
			end

			for i, waypoint in ipairs(waypoints) do
				if waypoint.Action == Enum.PathWaypointAction.Jump then
					Humanoid:ChangeState(Enum.HumanoidStateType.Jumping)
				end

				Humanoid:MoveTo(waypoint.Position)
				Humanoid.MoveToFinished:Wait()
			end
		end
	end
	
	task.wait()
end

while true do
	goal = FindNearestPlayer()

	if goal then
		pathFindTo(goal.Character.HumanoidRootPart.Position, goal)
	else
		task.wait(1)
	end
end

I am seeking guidance on how to implement a dynamic pathfinding system that updates in real-time as the player moves. The NPC should continuously recalculate its path every time the function is called. The real reason this happens is because of Humanoid.MoveToFinished:Wait(), but I can’t remove that without breaking the pathfinding system.

Thank you to anyone who can help.


p.s. please don’t tell me to use SimplePath or Forbidden API, they both have issues which is why im making a custom pathfinding system.

issues

SimplePath issue: does weird manuvers around corners and shakes a bunch, ONLY when constantly updating path (which i need to do). Forbidden API issue: pathfinder sometimes just starts pathing super slowly and freezes until the player starts moving.

I’m gonna see if I am able to do it and see if I can get it to work. May take a while though.

1 Like

So, I wasn’t able to find a valid solution to your problem that you are having yet because I only got to the point where it would update the path frequently, but then the NPC would stop moving until the player stopped moving. I may still mess around with it to see if I am able to find a fix to keep the NPC moving even while the player is moving and if that happens I will notify you.

Oh, removing the if destination ~= targetPosition then check fixes that issue.

1 Like

simply just check the distance from the current destination to the new destination (old player position, new player position) check if thats greater than a threshold (usually 1 stud is fine), if so update the path

do this once at each waypoint not at the end of the path. this should update enough. if its not enough then make the waypoints more condensed

What I did is I made a variable of each waypoint and add 1 each time the script loops. Simple, but effective. However, if I set the WalkSpeed to be higher than 16 it goes really slowly, so I have to mess with waypoint spacing, and after all of that, he works really well except for getting around corners. He goes kinda slow around corners unfortunately. Will follow up if I find a fix.

1 Like

check if path has at least 3 waypoints, then get the third path waypoint then and then do humanoid:moveto(waypoints[3].Position) in a loop

1 Like

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.