So I’m new to the pathfinding service in general, and in the process of scripting a pathfinding NPC that is intended to follow the player in a smart way, I did manage to get somewhere (as in: the NPC does follow the player). However, I continue to run into an annoying issue where the NPC appears to jitter about like it’s in some sort of existential confusion and panic about what exactly to do.
To better explain my troubles, I’ve provided a video here depicting the exact issue:
I’ve tried many methods that include “valid thread markers” using newproxy()
(Since events to alert for path re-calculation occur on seperate threads which theoretically could’ve resulted in the other movement threads still operating with an outdated path), to upping the path regen cooldown significantly, to stuff that only god knows since honestly I can’t even remember given the vast quantity of methods I tried.
I even looked around on here and found that my issue could be fixed via SetNetworkOwner(nil)
, but I’ve tried that and it still didn’t really work.
Can anyone help? Here is the script version that I am using so far:
local pathfindingService = game:GetService("PathfindingService")
for i,v in pairs(script.Parent:GetChildren()) do
if v:IsA("BasePart") then
v:SetNetworkOwner(nil)
end
end
local path = pathfindingService:CreatePath({
Costs = {
Ice = math.huge
}
})
local startNewPath = false
local waypoints = {}
local currentWaypoint = 0
function generateNewPath(destination)
if startNewPath then
return false
end
path:ComputeAsync(script.Parent.PrimaryPart.Position, destination)
startNewPath = true
return true
end
spawn(function()
local destination = nil
while true do
wait(1)
if destination == script.Destination.Value then
continue
end
if generateNewPath(script.Destination.Value) then
destination = script.Destination.Value
end
end
end)
path.Blocked:Connect(function(index)
if index > currentWaypoint then
generateNewPath(script.Destination.Value)
end
end)
while true do
if startNewPath then
currentWaypoint = 0
waypoints = path:GetWaypoints()
startNewPath = false
continue
else
currentWaypoint += 1
end
local stationary = false
if currentWaypoint > #waypoints then
stationary = true
currentWaypoint = #waypoints
end
local point = waypoints[currentWaypoint]
if not stationary then
if point.Action == Enum.PathWaypointAction.Jump then
script.Parent.Humanoid.Jump = true
end
script.Parent.Humanoid:MoveTo(point.Position)
script.Parent.Humanoid.MoveToFinished:Wait()
else
wait(0.1)
end
end
So I think I fixed it. It might error on later so I’ll make sure to update my post, but for now I managed to fix the jittering problem.
Essentially what caused it was the fact that ComputeAsync()
was being done on a seperate thread rather than the main one (which was intentional). I then made the path become visualized however and discovered that the reason the NPC was moving back and forth was because the path, due to being computed slightly in the past, had it’s first waypoint behind the current waypoint.
This then caused the NPC to move backwards as it tried to catch up on the new path, which then stacked as more paths got created, leaving the NPC a mess.
It still acts very hesitant though and walks very slowly, as if SetNetworkOwner
wasn’t being done, but that might just be because of the fact that I’m running the server locally rather than through an actual roblox server.
Here’s the updated code for those that might experience my same heartache in the future:
local pathfindingService = game:GetService("PathfindingService")
function recursiveNetOwner(children)
for i,v in pairs(children) do
if v:IsA("BasePart") then
pcall(function() v:SetNetworkOwner(nil) end)
end
recursiveNetOwner(v:GetChildren())
end
end
recursiveNetOwner(script.Parent:GetChildren())
local path = pathfindingService:CreatePath({
Costs = {
Ice = math.huge
}
})
local startNewPath = false
local pathRegenerated = false
local waypoints = {}
local currentWaypoint = 0
function generateNewPath()
if startNewPath then
return false
end
startNewPath = true
pathRegenerated = true
return true
end
spawn(function()
local destination = nil
while true do
wait(1)
if destination == script.Destination.Value then
continue
end
if generateNewPath() then
destination = script.Destination.Value
end
end
end)
path.Blocked:Connect(function(index)
if index >= currentWaypoint then
generateNewPath()
end
end)
local holder = Instance.new("Model", workspace)
while true do
if pathRegenerated then
currentWaypoint = 0
path:ComputeAsync(script.Parent.PrimaryPart.Position, script.Destination.Value)
if path.Status == Enum.PathStatus.NoPath then
generateNewPath()
continue
end
waypoints = path:GetWaypoints()
startNewPath = false
pathRegenerated = false
print("Continuing")
continue
else
print("Incremented waypoint")
currentWaypoint += 1
end
--[[holder:ClearAllChildren()
for i,v in pairs(waypoints) do
local p = Instance.new("Part", holder)
p.Anchored = true
p.CanCollide = false
p.Size = Vector3.new(1,1,1)
p.Position = v.Position
if i == currentWaypoint then
p.BrickColor = BrickColor.new("Really red")
end
end]]--
local stationary = false
if currentWaypoint > #waypoints then
print("Stationary at "..#waypoints.." ("..currentWaypoint..")")
stationary = true
currentWaypoint = #waypoints
end
local point = waypoints[currentWaypoint]
if not stationary then
if point.Action == Enum.PathWaypointAction.Jump then
print("Jump")
script.Parent.Humanoid.Jump = true
end
print("Going")
script.Parent.Humanoid:MoveTo(point.Position)
print("Waiting to reach")
if not script.Parent.Humanoid.MoveToFinished:Wait() then
generateNewPath()
end
else
wait(0.1)
end
end
4 Likes