# Pathfinding is making NPC movement choppy

So I’ve been experimenting with pathfinding on NPCs recently, and it seems as if all the movement of my NPCs are becoming choppy as they keep on moving. https://gyazo.com/c5b1bacbd724dd600231aabce434ebba

I’ve tried viewing other posts on the forum, but none of them really helped with my specific problem. What I’m trying to achieve is obviously a smoother and cleaner look to the walk of the NPC.

Now, what I’m basically doing with the NPCs is that I’m spawning a recursive function that decides and moves the NPC to a specific location. Frankly, I don’t know if it’s a good idea to spawn recursive functions, so if anyone has alternatives, that would be great. Anyways, in the function, I would then start to decide the destination of the NPC, and the path it would take. The function is listed below.

function NPC:ExecuteBehavior()
if self.Type == (“Roamer”) then

``````  local EligibleSpawns = {}

for i, Spawn in pairs(Workspace:WaitForChild("MovePoints"):GetChildren()) do
if (Spawn) ~= (self.Target) then
if (self.Target.Position.X) == (Spawn.Position.X) then
table.insert(EligibleSpawns, Spawn.Name)
end
if (self.Target.Position.Z) == (Spawn.Position.Z) then
table.insert(EligibleSpawns, Spawn.Name)
end
end
end
``````

local RandomSpawn = Workspace:WaitForChild(“MovePoints”):FindFirstChild(EligibleSpawns[math.random(1, > #EligibleSpawns)])

``````  self.Target = RandomSpawn

local Path = self:ComputePath(RandomSpawn)

for i, Waypoint in ipairs(Path:GetWaypoints()) do
self.NPC.Humanoid:MoveTo(Waypoint.Position)
self.NPC.Humanoid.MoveToFinished:Wait()
end

self:ExecuteBehavior()
``````

end
end

Also, here’s the script executing the functions.

for i = 1, 20 do
local b = a.new(“Roamer”)
spawn(function()
b:ExecuteBehavior()
end)
end

How would I be able to get rid of the choppiness of the NPCs? Also, any other feedback would be appreciated.

4 Likes

The NPCs most likely stutter because of the self.NPC.Humanoid.MoveToFinished:Wait() in your pathfinding waypoint table. You could try moving the NPCs into their waypoint just before they finish with their current one.

2 Likes

Alright, how exactly would I do this?

Would I just move the npc to their waypoint like .1 second before they reach it?

And if so, how exactly would I find the duration of how long it takes for the npc to get to their waypoint?

Sorry, I’m just a bit new to pathfinding, so any help would be appreciated.

While this would work in theory, I cannot guarantee 100% functionality based on dynamic changing environments. I do have a small catch in this code for that though:

``````local pointA = Vector3.new(0,0,0)
local pointB = Vector3.new(100,0,0)

local walkSpeed = 16
local distance = (pointB-pointA).magnitude

local timeTaken = distance/walkSpeed

wait(timeTaken-0.5)

if (pointB - AIPOSITION).magnitude < 0.5/walkSpeed + 0.1 then --check if the ai is close to the point, specifically, within half a stud
--finished
else
repeat -- continue waiting for the ai to get close
wait(0.05)
until (pointB - AIPOSITION).magnitude < 0.5/walkSpeed + 0.1
end``````
2 Likes

You can additionally establish a MoveToFinished listener event to yield and stop the loop early via a while true do loop that plays while the NPC is still moving.

``````-- example script moving Dummy to Dummy2

local PF = game:GetService("PathfindingService")

local path = PF:CreatePath()
path:ComputeAsync(script.Parent.Torso.Position, workspace.Dummy2.Torso.Position)

local wayPoints = path:GetWaypoints()

local RunService = game:GetService("RunService")

local DestPosition = Vector3.new(workspace.Dummy2.Torso.Position) -- Just as an example
local DistFactor = 3.3 -- Most regular-sized NPCs stop around 3 studs short from Torso - Waypoint Pos.
local Humanoid = script.Parent:WaitForChild("Humanoid")

for i = 1, #wayPoints do
local wP = wayPoints[i]
local wPDistance

Humanoid:MoveTo(wP.Position)

local MoveToFinished = false
local ListenConn
ListenConn = Humanoid.MoveToFinished:connect(function()
ListenConn:Disconnect()
MoveToFinished = true
end)

while MoveToFinished == false do
wPDistance = (script.Parent.Torso.Position - wayPoints[i].Position).magnitude
if wPDistance <= DistFactor then
ListenConn:Disconnect()
break
end
RunService.Heartbeat:wait()
end
end
``````

This uses roughly the same premise as @marfit did, only without speed.

3 Likes