Pathfinding Stuttering

I have seen this issue before with chasing AI, but all the solutions on the Dev Forum that I try don’t work.


If you don’t watch the video, I’ll just explain it here.
The main issue, which I’m sure most have seen this before, is the AI constantly stuttering to chase the player. I’ve never seen anyone ask this question about why the pathfinding works perfectly fine when the model is walking and not running at a faster speed?
Anyways, I’m hoping to look for a fix that works well and allows the AI to run at it’s normal speed to kill players.
Before anyone says stuff about Network Owner, I already have the Network Owner set to nil, so I don’t know another solution.
Here is the code that I’ve made and used for many years.

--[[ By: xXTerra_X. ]]--
local AiScript=script;
local Subject=AiScript.Parent;
if Subject:FindFirstChild("Thumbnail") then
Subject:FindFirstChild("Thumbnail"):Destroy();
end;
function GetHumanoid(Model)
for _, v in pairs(Model:GetChildren())do
if v:IsA'Humanoid' then
return v;
end;
end;
end;
local SubjectHumanoid=GetHumanoid(Subject);
local SubjectHumanoidRootPart=Subject:FindFirstChild("HumanoidRootPart");
local Pathing=Game:GetService("PathfindingService");
local Targets=Game:GetService("Players");
local NoticeDistance=99999;
local Vars=AiScript:FindFirstChild("Vars");
local Path;
local WayPoint;
local TargetName=nil;
local WanderX,WanderZ=30,30;
local DamageDebounce=false;
function GetTorso(Part)
local Targets=Game.Workspace:GetChildren();
local TargetRoot=nil;
local TargetTorso=nil;
local TargetPlayer=nil;
local FoundHumanoid=nil;
local NoticeDebounce=NoticeDistance;
for i = 1, #Targets do
TargetPlayer=Targets[i];
if TargetPlayer:IsA("Model") and TargetPlayer~=Subject then
FoundHumanoid=GetHumanoid(TargetPlayer);
TargetRoot=TargetPlayer:FindFirstChild("HumanoidRootPart");
if TargetRoot~=nil and FoundHumanoid~=nil and FoundHumanoid.Health>0 and FoundHumanoid.Name~="Zombie" then
if (TargetRoot.Position-Part).magnitude<NoticeDebounce then
TargetName=TargetPlayer.Name;
TargetTorso=TargetRoot;
NoticeDebounce=(TargetRoot.Position-Part).magnitude;
end;
end;
end;
end;
return TargetTorso;
end;
function GetPlayersBodyParts(Test)
local Torso=Test;
if Torso then
local Target=Torso.Parent;
for _, v in pairs(Target:GetChildren())do
if v:IsA("Part") then
return v.Name;
end;
end;
else
return "HumanoidRootPart";
end;
end;
Spawn(function()
while Wait(0)do
for _,V in pairs(Game:GetService("Workspace"):GetDescendants())do 
local FoundHumanoid=V:FindFirstChildOfClass("Humanoid");
local FoundHumanoidRootPart=V:FindFirstChild("HumanoidRootPart");
if V:IsA("Model")and FoundHumanoidRootPart and FoundHumanoid and V~=Subject and V.Parent~=Game:GetService("Workspace"):FindFirstChild("Killer Storage") and Subject.Parent==Game:GetService("Workspace"):FindFirstChild("Killer Storage")then
if(FoundHumanoidRootPart.Position-SubjectHumanoidRootPart.Position).Magnitude<=5 then
local MainTarget=FoundHumanoid.Parent;
if not MainTarget:FindFirstChildOfClass("ForceField")then
local TargetPlayer=Game:GetService("Players"):FindFirstChild(MainTarget.Name);
if not TargetPlayer.PlayerGui:FindFirstChild("JSGui")then
local JSGui=AiScript:FindFirstChild("JSGui"):Clone();
JSGui.Parent=TargetPlayer.PlayerGui;
JSGui:FindFirstChild("ImageLable"):FindFirstChild("Sound"):Play();
Vars.Attacking.Value=true;
FoundHumanoid:TakeDamage(99999e99999);
Vars.Attacking.Value=false;
end;
end;
end;
end;
end;
end;
end);
Spawn(function()
while Vars.Wandering.Value==false and SubjectHumanoid.Health > 0 do	
Vars.Chasing.Value=false;
Vars.Wandering.Value=true;
local desgx, desgz=SubjectHumanoidRootPart.Position.x+math.random(-WanderX,WanderX), SubjectHumanoidRootPart.Position.z+math.random(-WanderZ,WanderZ);
local function checkw(t)
local ci=3;
if ci>#t then
ci=3;
end
if t[ci]==nil and ci<#t then
repeat ci=ci+1 wait() until t[ci]~=nil;
return Vector3.new(1,0,0)+t[ci];
else
ci=3;
return t[ci];
end;
end;
Path=Pathing:FindPathAsync(SubjectHumanoidRootPart.Position,Vector3.new(desgx,0,desgz));
WayPoint=Path:GetWaypoints();
local connection;
local direct=Vector3.FromNormalId(Enum.NormalId.Front);
local ncf=SubjectHumanoidRootPart.CFrame*CFrame.new(direct);
direct=ncf.p.unit;
local rootr=Ray.new(SubjectHumanoidRootPart.Position,direct);
local phit,ppos=Game.Workspace:FindPartOnRay(rootr,SubjectHumanoidRootPart);
if Path and WayPoint or checkw(WayPoint) then
if checkw(WayPoint) ~= nil and checkw(WayPoint).Action==Enum.PathWaypointAction.Walk then
SubjectHumanoid:MoveTo( checkw(WayPoint).Position);
SubjectHumanoid.Jump=false;
end
if checkw(WayPoint)~=nil and checkw(WayPoint).Action==Enum.PathWaypointAction.Jump then
connection=SubjectHumanoid.Changed:connect(function()
SubjectHumanoid.Jump=true;
end)
SubjectHumanoid:MoveTo(WayPoint[4].Position);
else
SubjectHumanoid.Jump=false;
end
if connection then
connection:Disconnect()
end;
else
for i=3,#WayPoint do
SubjectHumanoid:MoveTo(WayPoint[i].Position);
end;
end;
Wait(math.random(1,2));
Vars.Wandering.Value=false;
end
end)
while Wait() do
local nrstt=GetTorso(SubjectHumanoidRootPart.Position)
if nrstt~=nil and SubjectHumanoid.Health > 0 then
Vars.Wandering.Value=false;
Vars.Chasing.Value=true;
local function checkw(t)
local ci = 3
if ci > #t then
ci = 3
end
if t[ci]==nil and ci<#t then
repeat ci=ci+1 Wait() until t[ci]~=nil;
return Vector3.new(1,0,0)+t[ci];
else
ci = 3;
return t[ci];
end;
end;
Path=Pathing:FindPathAsync(SubjectHumanoidRootPart.Position,nrstt.Position);
WayPoint=Path:GetWaypoints();
local connection;
local direct=Vector3.FromNormalId(Enum.NormalId.Front);
local ncf=SubjectHumanoidRootPart.CFrame*CFrame.new(direct);
direct=ncf.p.unit;
local rootr=Ray.new(SubjectHumanoidRootPart.Position,direct);
local phit,ppos=Game.Workspace:FindPartOnRay(rootr,SubjectHumanoidRootPart);
if Path and WayPoint or checkw(WayPoint) then
if checkw(WayPoint)~=nil and checkw(WayPoint).Action==Enum.PathWaypointAction.Walk then
SubjectHumanoid:MoveTo( checkw(WayPoint).Position);
SubjectHumanoid.Jump=false;
end;
if checkw(WayPoint)~=nil and checkw(WayPoint).Action==Enum.PathWaypointAction.Jump then
connection=SubjectHumanoid.Changed:connect(function()
SubjectHumanoid.Jump=true;
end);
SubjectHumanoid:MoveTo(WayPoint[4].Position);
else
SubjectHumanoid.Jump=false;
end
if connection then
connection:Disconnect();
end;
else
for i=3,#WayPoint do
SubjectHumanoid:MoveTo(WayPoint[i].Position);
end;
end;
Path=nil;
WayPoint=nil;
elseif nrstt==nil then
Vars.Wandering.Value=false;
Vars.Chasing.Value=false;
TtargetName=nil;
Path=nil;
WayPoint=nil;
SubjectHumanoid.MoveToFinished:Wait();
end;
end;
--[[ By: xXTerra_X. ]]--

All help is appreciated and I hope to find a well worked solution. Thanks

Instead of while loops, I suggest ysing runservice I normally use heartbeat or renderstepped or whatever, it will make it much more smoother imo

I’ve seen people tell others not to use RunService, but I will try it

1 Like

Runservice is decent imo, depends how you use it also make sure you make it a connection so you can disconnect it afterwards when it’s no longer needed

Okay this worked extremely well and the AI ran perfectly. My one problem is the game runs slow using hearbeat and gets even slower overtime.
So I made it a connection and added my disconnect code for when it’s not being used, but with that addition the AI barely moves and when a player is killed, it stops moving entirely.
Though that could have to deal with the placement of the disconnect code so I will try placing it somewhere else and I will note about it

Even placing the disconnecting code makes it run slow so I don’t know any solution to the game speed.

Without looking at the code … I’ve had this happen before. It came from the timing between go to next waypoint. In this case you’re waiting just a bit too long.

Assuming your animation is working correctly.

Set it up so it checks more in a loop that can fail and keep going till it’s on the next waypoint.

There are no waits to go to the waypoints. Because I know by doing this then the AI will have a delay every time it reaches a waypoint. Basically going to where the player WAS instead of where the player IS.

I meant to say point … but seen waypoint in the code.
May be off here. But, I fixed mine as I said in the last line of the last post.

Could I see the code of yours for this? This is really frustrating for me when all fixes I try don’t work.

Mine is way different than yours … Don’t think it will be much help to fix your script.

Damn, I still would like to see it so I can see how I can possibly look at it and try to improve mine. I know you said yours is completely different, but I can try transferring the code in a way for mine to maybe work

I just looked at it. Unfortunately it’s not my most generic work and it’s a bit tied in to too many things for the game I use it for. Really should remake a generic one.

maybe this will help, if you can figure out a way to implement it

local function Move(destination)
    local startTime = tick()
    local duration = 1
    
    while tick() - startTime < duration do
        local elapsedTime = tick() - startTime
        local lerpFactor = math.min(1, elapsedTime / duration)
        
        SubjectHumanoid:MoveTo(Vector3.Lerp(SubjectHumanoidRootPart.Position, destination, lerpFactor))
        wait()
    end
    
    SubjectHumanoid:MoveTo(destination)
end

I sent you a PM code … if it isn’t working maybe someone else can help.

Think about this one, one other thing that can make them stutter like that is when the points they are moving to are too close together.

can i see the code please, This will help me find out why it’s running slow.