Waypoint is incorrect

i have a script where an npc goes to a player and once its close to the player the npc will go to a random part (waypoint) using pathfinding.
the problem is that when i print the waypoints position, instead of printing the parts position its supposed to go to it prints the players position
i will post the full code im using + comments so you can understand more:


--------------------------
local destination = workspace.NunPath:GetChildren() 
local points = {} 
for _,part in ipairs(destination) do ------these are the Parts the NPC is SUPPOSED to go to AFTER getting close to the player
	table.insert(points,part)
	task.wait()
end
-----------------------
local function findTarget()
	local players = game:GetService("Players"):GetPlayers()
	local nearesttarget
	local maxDistance = 5000 -- distance

	for i,player in pairs(players) do
		if player.Character then
			local target = player.Character
			local distance = (npc.HumanoidRootPart.Position - target:WaitForChild("HumanoidRootPart").Position).Magnitude

			if distance < maxDistance and IsTalking.Value == false then
				nearesttarget = target
				maxDistance = distance
			end

			if distance <= TalkDistance  then
				human.WalkSpeed = 26
				IsTalking.Value = true
				if not TalkDebounce then
				TalkDebounce = true
				RunPlayerAnim:Play()
				end
			
				local point = points[math.random(1,#points)] --this chooses a random POINT (like i stated above)
				--local path = getPath(RandomSafeArea.Position)
				local path = PFS:CreatePath({
					AgentRadius = 2,
					AgentHeight = 5,
					AgentCanJump = true
				})
				print(point) --THIS PRINTS CORRECTLY
				path:ComputeAsync(npc.HumanoidRootPart.Position, point.Position)
				print(point.Position) --THIS PRINTS CORRECTLY
				if path.Status ~= Enum.PathStatus.Success then
					warn("noooooooooooo path failed")
				end
				for _, waypoint in pairs(path:GetWaypoints()) do
				print("should be working")
				print(waypoint.Position) ------------PRINTS INCORRECTLY!!! THIS IS THE PROBLEM!!!
					if waypoint.Action == Enum.PathWaypointAction.Jump then
						human.Jump = true
					end
					if waypoint.Action == Enum.PathWaypointAction.Walk then
						human:ChangeState(Enum.HumanoidStateType.Running)
					end
					print("Moving Player")
					human:MoveTo(waypoint.Position)
					human.MoveToFinished:Wait()

				end
			end

		end
	end
	return nearesttarget
end


local function pathFindTo(destination)
	local path = getPath(destination)
	local target = findTarget()

if target and target.Humanoid.Health > 0 and IsTalking.Value == false then
	for i,waypoint in pairs(path:GetWaypoints()) do

		if waypoint.Action == Enum.PathWaypointAction.Jump then
			human.Jump = true
		end
		print("Move to player")
		human:MoveTo(waypoint.Position)
		human.MoveToFinished:Wait()

if CheckRaycast() == true then -- you're going to have to make your own checkraycast function
	repeat
		human:MoveTo(target.PrimaryPart.Position)
		task.wait()
	until CheckRaycast() == false
	break
end
	end
end
end

while true do
	task.wait()
	local target = findTarget()

	if target and IsTalking.Value == false then
		print("Attacking"..target.Name)
		pathFindTo(target:WaitForChild("HumanoidRootPart").Position)
	end
end

There’s settings you can change with PathfindingService.
Replace

local path = PFS:CreatePath({
	AgentRadius = 2,
	AgentHeight = 5,
	AgentCanJump = true
})

with

local path = PFS:CreatePath({
	AgentRadius = 2,
	AgentHeight = 5,
	AgentCanJump = true,
	WaypointSpacing = math.huge
})

and tell me if you’re still getting the problem.

same problem still, waypoint is still incorrect

Try doing warn(typeof(waypoint)). Check if the type is an actual PathWaypoint.

1 Like

yeah it is (if it wasnt the for loop wouldnt work right?)

Could you show a video of the unexpected behavior? Would help a lot to visualize what the problem is.

trust me a video wouldnt help. ill try to simplify exactly what the script does:
first, the NPC finds a player and goes towards it. once the NPC is close enough to the player, the player wont be able to move and they get welded to the NPC. The npc now SHOULD go to a random part on the map.
however, the npc doesnt go to the random part and instead goes for the player. i posted the full script so you could examine it

fixed it using local waypoint = PathWaypoint.new(pos, Enum.PathWaypointAction.Walk)

Pathwaypoint.Position is not the position of the goal, is that’s what you’re saying.

What is pos in your script?

then what is it

the position???

It’s the position of the waypoint, aka a point that’s part of a path that goes from the starting position to the goal position. That’s the basis of using PathfindingService, there would be no point in the waypoint’s position simply being the position of the goal since you need to know the position of the goal to generate the path in the first place.

Of what? The goal? Maybe you should look more into pathfinding if you sincerely believe all the possibly hundreds of waypoints that are generated are just the goal position the script already knows, thereby achieving absolutely nothing other than using up memory.

so its just a random part of the path

bro what are you talking about i literally solved this already

Not random, it gives a list of positions where, if you walk over to them in order, you will reach the destination.

If pos is just the goal position, a question you haven’t even answered, then it isn’t working properly. Have you tried putting some walls in the NPC’s way and seeing if it can find it’s way around them?

1 Like

makes sense

pos is the goal position, yes. also your correct it isnt working right (to be specific, the npc doesnt actually go to it, it just kinda ignores it) and yes there are walls and objects in the way.
btw, when i said i solved it already, i mostly meant the waypoints position its printing correctly, so thanks for posting to show that i was wrong
here is the full code if you wanna look at it to improve my code:

local npc = script.Parent
local human = npc.Humanoid

local PFS = game:GetService("PathfindingService")
local RUNSERVICE = game:GetService("RunService")

npc.PrimaryPart:SetNetworkOwner(nil)
task.wait(20)

local IsTalking = npc.IsTalking
local TalkDebounce = false
local TalkDistance = 4

local IsFriendly = npc.IsFriendly

local IdleAnim = human.Animator:LoadAnimation(npc.Idle)
local WalkAnim = human.Animator:LoadAnimation(npc.Walk)
local RunAnim = human.Animator:LoadAnimation(npc.Run)

local Doors = workspace.Doors:GetChildren()

human.WalkSpeed = 8

local function getPath(destination)
	local path = PFS:CreatePath()

	path:ComputeAsync(npc.HumanoidRootPart.Position, destination)

	return path
end
--------------------------
local destination = workspace.NunPath:GetChildren() 
local points = {} 
for _,part in ipairs(destination) do ------these are the Parts the NPC is SUPPOSED to go to AFTER getting close to the player
	table.insert(points,part)
	task.wait()
end
-----------------------
local function findTarget()
	local players = game:GetService("Players"):GetPlayers()
	local nearesttarget
	local maxDistance = 5000 -- distance

	for i,player in pairs(players) do
		if player.Character then
			local target = player.Character
			local distance = (npc.HumanoidRootPart.Position - target:WaitForChild("HumanoidRootPart").Position).Magnitude

			if distance < maxDistance and IsTalking.Value == false then
				nearesttarget = target
				maxDistance = distance
			end

			if distance <= TalkDistance  then
				human.WalkSpeed = 26
				IsTalking.Value = true
				--print(IsTalking.Value)
				if not TalkDebounce then
				TalkDebounce = true

				local RunPlayerAnim = target.Humanoid.Animator:LoadAnimation(npc.RunPlayer)
				target.WalkSpeedValue.Value = 0
				target.Humanoid.WalkSpeed = 0
				RunPlayerAnim:Play()
				local Weld = Instance.new("WeldConstraint")
				Weld.Part0 = target.HumanoidRootPart
				Weld.Part1 = npc.HumanoidRootPart
				Weld.Parent = target.HumanoidRootPart
				human.WalkSpeed = 26
				end
				local ClosestDoor = nil
				for i, v in pairs(Doors) do
					local distanceFromDoors = (npc.HumanoidRootPart.Position - v.PrimaryPart.Position).Magnitude
					if distanceFromDoors < 5 then
						print("Near Door")
						print(v)
					end
				end


				local point = points[math.random(1,#points)] --this chooses a random POINT (like i stated above)
				--local path = getPath(RandomSafeArea.Position)
				local newPath = PFS:CreatePath({
					AgentRadius = 2,
					AgentHeight = 5,
					AgentCanJump = true,
					WaypointSpacing = math.huge
				})
				print(point) --THIS PRINTS CORRECTLY
				newPath:ComputeAsync(npc.HumanoidRootPart.Position, point.Position)
				print(point.Position) --THIS PRINTS CORRECTLY
				if newPath.Status ~= Enum.PathStatus.Success then
					warn("noooooooooooo path failed")
				end
				local waypoint = PathWaypoint.new(point.Position, Enum.PathWaypointAction.Walk)
				--for _, waypoint in ipairs(newPath:GetWaypoints()) do
				print("should be working")
				print(waypoint.Position) ------------PRINTS INCORRECTLY!!! THIS IS THE PROBLEM!!!
					if waypoint.Action == Enum.PathWaypointAction.Jump then
						human.Jump = true
					end
					if waypoint.Action == Enum.PathWaypointAction.Walk then
						human:ChangeState(Enum.HumanoidStateType.Running)
					end
					print("Moving Player")
					human:MoveTo(waypoint.Position)
					human.MoveToFinished:Wait()
					print("Nun Moved Player To Safe Area")
					local RandomAggro = math.random(1,2)
					if RandomAggro == 1 then
						print("Friendly")
					else
						print("Aggro")
						target.Head:Destroy()
						target.Humanoid.Health = 0
					end
				end
			--end

		end
	end
	return nearesttarget
end

local function CheckRaycast()
	local target = findTarget()
	if target and not IsTalking.Value then
	local ray = Ray.new(npc.HumanoidRootPart.Position,(target.HumanoidRootPart.Position - npc.HumanoidRootPart.Position).unit * 100) -- create the ray
	local hit,pos = workspace:FindPartOnRay(ray,npc) -- find parts that the ray hit

	if hit then -- if the ray hit a part then
		if hit:IsDescendantOf(target) then -- if the part is part of the target's character then
			return true -- return true
		end
	end
	--IsAttacking.Value = false
	return false -- if no target was found, return false
	end
end

local function pathFindTo(destination)
	local path = getPath(destination)
	local target = findTarget()

if target and target.Humanoid.Health > 0 and IsTalking.Value == false then
	for i,waypoint in pairs(path:GetWaypoints()) do

		if waypoint.Action == Enum.PathWaypointAction.Jump then
			human.Jump = true
		end
		print("Move to player")
		human:MoveTo(waypoint.Position)
		human.MoveToFinished:Wait()

if CheckRaycast() == true then -- you're going to have to make your own checkraycast function
	repeat
		human:MoveTo(target.PrimaryPart.Position)
		task.wait()
	until CheckRaycast() == false
	break
end
	end
end
end

human.Running:Connect(function(speed)
	if speed > 1 and speed < 15 then
		WalkAnim:Play()
		IdleAnim:Stop()
		RunAnim:Stop()
	end
	if speed <= 1 then
		IdleAnim:Play()
		WalkAnim:Stop()
		RunAnim:Stop()
	end
	if speed >= 15 then
		RunAnim:Play()
		WalkAnim:Stop()
		IdleAnim:Stop()
	end
end)

while true do
	task.wait()
	local target = findTarget()

	if target and IsTalking.Value == false then
		print("Attacking"..target.Name)
		pathFindTo(target:WaitForChild("HumanoidRootPart").Position)
	end
end

You aren’t doing anything with the path

The NPC is effectively walking in a straight line towards the destination (or, most likely, erroring before it can call :MoveTo).

Is there anything in the output? Maybe now’s the time to un-comment the for-loop and see if there are issues with the path itself.

Remove this as well. waypoint should not be the goal position (point.Position in this case).

1 Like

seems that way, in the video you can see that there is an upstairs and the waypoint is upstairs.

nothing in the output other than my print statements


so with the code i have now (the same code expect i did what you said and commented out the Weld cause it was getting in the way) the npc actually successfuly gets into a room (ignore the part where the NPC runs into a wall)
this is the for loop rn

if not TalkDebounce then
for _, waypoint in ipairs(newPath:GetWaypoints()) do
				print("should be working")
				print(waypoint.Position) ------------PRINTS INCORRECTLY!!! THIS IS THE PROBLEM!!!
					if waypoint.Action == Enum.PathWaypointAction.Jump then
						human.Jump = true
					end
					if waypoint.Action == Enum.PathWaypointAction.Walk then
						human:ChangeState(Enum.HumanoidStateType.Running)
					end
					print("Moving Player")
					human:MoveTo(waypoint.Position)
					human.MoveToFinished:Wait()
					print("Nun Moved Player To Safe Area")
					local RandomAggro = math.random(1,2)
					if RandomAggro == 1 then
						print("Friendly")
					else
						print("Aggro")
						--target.Head:Destroy()
						--target.Humanoid.Health = 0
					end
				end
            end

You don’t need to do this, the state is changed whenever the Humanoid is given any input, through MoveTo in your game.

1 Like

so i found another error. sometimes when the for loop is called pathfinding thinks it instantly completed the path. (sometimes when the npc starts to make a path, the script thinks the path was completed) (i put some comments and removed unnecessary stuff)
this is some code:

if not TalkDebounce then
					TalkDebounce = true
				local point = points[math.random(1,#points)] 

				local newPath = PFS:CreatePath({
					AgentRadius = 2,
					AgentHeight = 5,
					AgentCanJump = true,
					Costs = {
					NunPathModifier = math.huge
					},
					WaypointSpacing = math.huge
				})

				newPath:ComputeAsync(npc.HumanoidRootPart.Position, point.Position)

				if newPath.Status ~= Enum.PathStatus.Success then
					warn("noooooooooooo path failed")
				end
				--if CompletedPath == false then
				for _, waypoint in ipairs(newPath:GetWaypoints())  do
					
					--if not CompletedPath then

					if waypoint.Action == Enum.PathWaypointAction.Jump then
						human.Jump = true
					end
					if waypoint.Action == Enum.PathWaypointAction.Walk then
						human:ChangeState(Enum.HumanoidStateType.Running)
					end
					print("Moving Player")
					human:MoveTo(waypoint.Position)
					human.MoveToFinished:Wait()
					print("finished") --Sometimes prints this as soon as the for loop code runs
					--CompletedPath = false
					if CompletedPath == false then
						CompletedPath = true
					newPath:Destroy()
					human.WalkSpeed = 0
					
					print("Nun Moved Player To Safe Area")
					local RandomAggro = math.random(2,2)
					if RandomAggro == 1 then
						print("Friendly")
						game:GetService("ReplicatedStorage").NunAttackFinished:FireClient(game.Players:GetPlayerFromCharacter(target))
					else
						print("Aggro")
						local tween = game:GetService("TweenService"):Create(target.Head, TweenInfo.new(.25, Enum.EasingStyle.Linear), {CFrame = target.Head.CFrame * CFrame.Angles(0,0,math.rad(180))})
						--target.Head.CFrame *= CFrame.Angles(0,0,math.rad(180))
						tween:Play()
						task.wait(.25)
						target.Humanoid.Health = 0
					end
					end
					--end
				end

Try adding this;

local part = Instance.new("Part")
part.Material = Enum.Material.Neon
part.Position = waypoint.Position
part.Size = Vector3.new(1, 1, 1)
part.Shape = Enum.PartType.Ball
part.CanCollide = false
part.Anchored = true
part.Name = "VisualWaypoint"
part.Parent = workspace

to the top of the for loop. See if the glowing dots form a path towards the goal.

1 Like

Well, I don’t think movetofinished is actually meant for reaching the last waypoint. I think movetofinished is meant for reaching every waypoint.

Maybe your problem is you haven’t cancelled the waypoint by using break, and if not, try visualizing or displaying the path so you will be able to see if your path is incorrect or inefficient.

Instead of destroying the path, Why not try path:Stop() or cancel the waypoints inside of the for loop just by putting the break here with the right timing?

1 Like