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
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
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.
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?
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
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
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
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?