In this issue, we are using PathfindingService alongside Humanoid:MoveTo
.
When we call Humanoid:MoveTo() from waypoint to waypoint, and use the MoveToFinished event to detect when the character reaches each waypoint it does work, however unlike the demo place and code portrayed in the documentation on Character Pathfinding, many games such as ours will not operate with smoothness due to the event having a delay on being communicated, leaving a stuttering NPC between nodes and overall a poor visual effect.
This is detrimental on considering performance in public games, unlike test baseplates with minimal events and memory.
The solution’s attempted include setting Network Ownership to nil on all BaseParts and MeshParts.
My approach to using this was as followed:
Path being passed through followpath method
local path = PathfindingService:CreatePath({
WaypointSpacing = 5,
Costs = {
RailwayTrack = math.huge,
Trees = math.huge,
Grass = 10,
LeafyGrass = 10,
GrassPart = 10,
Road = 0,
Crossing = 0,
DiamondPlate = 0,
Railing = math.huge
},
AgentCanJump = true,
AgentCanClimb = true,
AgentHeight = 3,
AgentRadius = 2
})
local function BeginPath(Rig, path, primaryDestination)
local success, errorMessage = pcall(function()
path:ComputeAsync(Rig.HumanoidRootPart.Position, primaryDestination)
end)
if success and path.Status == Enum.PathStatus.Success then
waypoints = path:GetWaypoints()
-- Detect if path becomes blocked
blockedConnection = Janitor:Add(path.Blocked:Connect(function(blockedWaypointIndex)
if blockedWaypointIndex >= nextWaypointIndex and tries <= 3 then
for _, player in ipairs(game.Players:GetPlayers()) do
if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
local distance = (Rig.HumanoidRootPart.Position - player.Character.HumanoidRootPart.Position).magnitude
if distance < closestPlayerDistance then
closestPlayerDistance = distance
closestPlayer = player
end
end
end
if closestPlayer then
local furthestPoint = findFurthestPointFromPlayer(Rig, closestPlayer.Character.HumanoidRootPart.Position)
if furthestPoint then
BeginPath(Rig, path, furthestPoint)
Rig.Humanoid.WalkSpeed = 29
else
tries += 1
BeginPath(Rig, path, primaryDestination)
end
end
elseif tries > 7 then
_remotes.Blocked:Fire()
print(`[NPCService > Path]: Path is blocked, terminating this attempt.`)
if Janitor then Janitor:Cleanup()
end
end
end))
-- Detect when movement to next waypoint is complete
if not reachedConnection then
reachedConnection = Janitor:Add(Rig.Humanoid.MoveToFinished:Connect(function(reached)
for i,v in pairs(script.Parent:GetDescendants()) do
if v:IsA("Part") or v:IsA("MeshPart") then
v:SetNetworkOwner(nil)
end
end
if reached and nextWaypointIndex < #waypoints then
nextWaypointIndex += 1
for _, player in ipairs(game.Players:GetPlayers()) do
if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
local distance = (Rig.HumanoidRootPart.Position - player.Character.HumanoidRootPart.Position).magnitude
if distance < closestPlayerDistance then
closestPlayerDistance = distance
closestPlayer = player
end
end
end
if closestPlayer and Fleeing == false and EligableToFlee == true then
local furthestPoint = findFurthestPointFromPlayer(Rig, closestPlayer.Character.HumanoidRootPart.Position)
Fleeing = true
nextWaypointIndex = 2
BeginPath(Rig, path, furthestPoint)
else
Rig.Humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
end
else
if Fleeing then
for _, player in ipairs(game.Players:GetPlayers()) do
if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
local distance = (Rig.HumanoidRootPart.Position - player.Character.HumanoidRootPart.Position).magnitude
if distance < closestPlayerDistance then
closestPlayerDistance = distance
closestPlayer = player
end
end
end
if closestPlayer and EligableToFlee == true then
local furthestPoint = findFurthestPointFromPlayer(Rig, closestPlayer.Character.HumanoidRootPart.Position)
Fleeing = true
nextWaypointIndex = 2
BeginPath(Rig, path, furthestPoint)
_remotes.Reached:Fire(Fleeing)
end
else
_remotes.Reached:Fire(Fleeing)
if Janitor then Janitor:Cleanup()
end
end
end
end))
end
nextWaypointIndex = 2
Rig.Humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
return -1
end
end
Expected behavior
If everything was running as expected, there should be a smooth transition between each path node.
Instead, the NPC stutters after reaching a node before moving off.
Evidence
See @Dlimerick’s post here: NPC :MoveTo has a stuttering effect whilst using PathfindingService - #11 by Dlimerick