How to update path of an NPC when an object moves

I’m having some trouble trying to figure out how to update the path of an NPC that targets the player, (Nearest, but that’s not implemented yet so it’s not in the code example)

Currently, the NPC will just go to the last known position of the player, obviously because it wants to finish the for loop first, but I want it to update its path at least relatively frequently/when the player is outside of the range of the last waypoint.

local players = game:GetService("Players")
local RunService = game:GetService('RunService')

local human = script.Parent:WaitForChild("Humanoid")
local body = script.Parent:WaitForChild("HumanoidRootPart")

local pathParams = {
	["AgentHeight"] = 8,
	["AgentRadius"] = 5,
	["AgentCanJump"] = false
}

function pathToNearestPlayer()
	local PlayerPath = pathFindingService:CreatePath(pathParams)
	for _,plr in pairs(players:GetPlayers()) do
		local char = plr.Character
		local playerRoot = char:FindFirstChild("HumanoidRootPart")
		local playerPos = playerRoot.Position
		PlayerPath:ComputeAsync(body.Position,playerPos)
	end
	return PlayerPath
end

--I mainly added wait here temporarily since the code runs into an error if it runs without a player present
wait(4)
while true do
	path = pathToNearestPlayer()
	local waypoints = path:GetWaypoints()
	for i, waypoint in pairs(waypoints) do
		path = pathToNearestPlayer()
		human:MoveTo(waypoint.Position)
		human.MoveToFinished:Wait(1)
	end
end

I have attempted the latter of comparing the distance of the player and the last waypoint and trying to break the loop with that, but any case where break is used in the for loop seems to completely break the NPC’s ability to move at all.

Does anyone have any advice? I’m at a loss.

I’m aware that this has been posted a lot, but as it stands none of the solutions I’ve seen nor have any of the videos supplied in other threads in regards to this issue have been understandable to me, kind of a me issue there so, apologies.

If it matters at all, it’s intended as an enemy script, so I’d need them to get close to attack.

Thank you in advance!

1 Like

You could also check the waypoint index to avoid this issue.

And yes, you would need the target’s HumanoidRootPart (or any other preferred body part).

if i > 8 and (targetHRP.Position - waypoint[#waypoint].Position).Magnitude > 3 then
	-- recalculate path
	break
end
1 Like

Alright, I threw it in with a target position, but it’s throwing this error at me;

“Workspace.Specimen 2.BasicMonsterHandle:59: attempt to get length of a PathWaypoint value”

Gonna be honest here, I don’t fully understand what’s going on in what you sent but an error was to be expected I suppose with me throwing it in haphazardly.

I’m relatively new to messing around with paths so I guess the confusion is normal. How would I go around fixing the error though?

1 Like

Okay, try this out instead:

I was accessing your PathWaypoint instead of the actual path.

if i > 8 and (targetHRP.Position - waypoints[#waypoints].Position).Magnitude > 3 then
	-- recalculate path
	break
end
1 Like

Alright, no error now, thank you

however, it doesn’t seem to be interrupting the loop and only triggers when the player is WAY far away from the NPC, or just, inconsistently in general, triggering when I’m standing still sometimes

Example of how far I had to be for it to start firing.

Sorry to take up your time like this, really don’t mean to be a pain.

2 Likes

Could you show your code?

[dont mind this]

1 Like

Sure thing, here;

local players = game:GetService("Players")
local RunService = game:GetService('RunService')

local human = script.Parent:WaitForChild("Humanoid")
local body = script.Parent:WaitForChild("HumanoidRootPart")

local pathParams = {
	["AgentHeight"] = 8,
	["AgentRadius"] = 5,
	["AgentCanJump"] = false
}



local function getclosestplr()
	local bot_position = body.Position

	local distance = math.huge
	local closest_player_character = nil

	for _,plr in pairs(players:GetPlayers()) do
		local player = plr.Character 
		if player:FindFirstChild("Humanoid") then

			local player_position = player.HumanoidRootPart.Position
			local distance_from_bot = (bot_position - player_position).magnitude

			if distance_from_bot < distance then
				distance = distance_from_bot
				closest_player_character = player
			end
		end
	end
	return closest_player_character
end

function pathToNearestPlayer()
	local plr = getclosestplr()
	local PlayerPath = pathFindingService:CreatePath(pathParams)
	PlayerPath:ComputeAsync(body.Position,plr.HumanoidRootPart.Position)
	return PlayerPath
end

wait(6)
while true do
	path = pathToNearestPlayer()
	local waypoints = path:GetWaypoints()
	for i, waypoint in pairs(waypoints) do
		human:MoveTo(waypoint.Position)
		human.MoveToFinished:Wait()
		local plr = getclosestplr()
		if i > 8 and (plr.HumanoidRootPart.Position - waypoints[#waypoints].Position).Magnitude > 1 then
			-- recalculate path
			print ("Recalculating path")
			break
		end
	end
end```

Different from the one before specifically to fix finding the closest player, also so I could use it in your if statement to get the player's HRP pos.
1 Like

Maybe it’s because of wait(6)?

I tried out your script and it seemed to work perfectly fine (no matter how far I was).

1 Like

The wait is there since my player needs to spawn otherwise getting player returns nill, it’s just temporary for the most part but I don’t think it’d affect it given it’s before the while loop.

Strange that it’s working for you though… Is the positioning of the if statement wrong in my script by chance? Like would it need to come before movetofinished or moveto?

Fixed! Thank you, you put me on the right path

I simply just swapped "Waypoints and targetHRP position and it works like a charm now.

Example below for anyone who comes across this.

if (waypoints[#waypoints].Position - targetHRP.Position).Magnitude > 5 then
	-- recalculate path
	print ("Player moved, Recalculating path")
	break
end```

the npc just stops after the loop breaks

while true do
local target = require(script.Parent.Targets).findNearestTarget()
	
	if target then
		local path = pfs:CreatePath()
		path:ComputeAsync(npc.PrimaryPart.Position, target.PrimaryPart.Position)
		
		local waypoints = path:GetWaypoints()
		
		for _, waypoint in waypoints do
			local distanceToPlayer = (target.PrimaryPart.Position - npc.PrimaryPart.Position).Magnitude
			
			print("Peter is", math.round(distanceToPlayer), "studs away from", target.Name)
			
			if (waypoints[#waypoints].Position - target.PrimaryPart.Position).Magnitude > 2 then
				break
			end
			
			if distanceToPlayer > 3 then
				npc.Humanoid:MoveTo(waypoint.Position)
				npc.Humanoid.MoveToFinished:Wait()
			else
				break
			end
		end
	end
	
	task.wait()
end