NPC twitches when pathfinding

As you can see, while moving, it occasionally twitches. This didn’t happen if I compute paths once the humanoid as reached its destination, but i’m doing a chase NPC.

local AIFolder=workspace:WaitForChild("AI")
local Players=game:GetService("Players")
local PathfindService=game:GetService("PathfindingService")
local RunService=game:GetService("RunService")


local CachedHumanoidRootParts={}

Players.PlayerAdded:Connect(function(localplr)
	localplr.CharacterAdded:Connect(function(char)
		CachedHumanoidRootParts[localplr]=char:FindFirstChild("HumanoidRootPart")
	end)
end)
Players.PlayerRemoving:Connect(function(localplr)
	CachedHumanoidRootParts[localplr]=nil
end)

local CurrentPathsInProgress={}
local NPCstats={}
local function VisualizePath(path, npc)

	if npc:FindFirstChild("DebugPath") then
		npc.DebugPath:Destroy()
	end

	
	local folder=Instance.new("Folder")
	folder.Name="DebugPath"
	folder.Parent=npc

	for i, waypoint in ipairs(path:GetWaypoints()) do
		local part=Instance.new("Part")
		part.Size=Vector3.new(0.5, 0.5, 0.5) 
		part.Shape=Enum.PartType.Ball
		part.Color=Color3.fromRGB(0, 255, 0) 
		part.Anchored=true
		part.CanCollide=false
		part.Position=waypoint.Position
		part.Parent=folder

		if waypoint.Action==Enum.PathWaypointAction.Jump then
			part.Color=Color3.fromRGB(255, 0, 0)
		end
	end
end

local function ComputeNewPath(HRP, destination, hum, npc)
	
	CurrentPathsInProgress[npc]=nil
	
	
	local path=PathfindService:CreatePath({
		AgentRadius=2,
		AgentHeight=5,
		AgentCanJump=true,
		AgentJumpHeight=7.5,
		AgentMaxSlope=45,
	})

	path:ComputeAsync(HRP.Position, destination.Position)

	if path.Status==Enum.PathStatus.Success then
	
		CurrentPathsInProgress[npc]=true
		VisualizePath(path, npc)
		task.spawn(function()
			
			

			for _, waypoint in ipairs(path:GetWaypoints()) do
				

					if not CurrentPathsInProgress[npc] then break end
				
					if waypoint.Action==Enum.PathWaypointAction.Jump then
						hum:ChangeState(Enum.HumanoidStateType.Jumping)
					end

					hum:MoveTo(waypoint.Position)
					hum.MoveToFinished:Wait()
				
			end

			CurrentPathsInProgress[npc]=nil
			
			
		end)
		
	else
		CurrentPathsInProgress[npc]=nil
	end
end




local LastCheck=tick()
local CheckInterval=.5
local CheckRadius=200
RunService.Heartbeat:Connect(function(dt)
	if tick()-LastCheck>=CheckInterval then
		LastCheck=tick()
		for i, npc in pairs(AIFolder:GetChildren()) do
			if npc:IsA("Model") and npc:FindFirstChildOfClass("Humanoid") then
				local NPChum=npc:FindFirstChild("Humanoid")
				local NPChumRoot=npc:FindFirstChild("HumanoidRootPart")
				for plr,humroot in pairs(CachedHumanoidRootParts) do
					local dist=(humroot.Position-NPChumRoot.Position).Magnitude
					if dist<=CheckRadius  then
						
						ComputeNewPath(NPChumRoot, humroot, NPChum,npc)
					
					end
				end
			end

		end
	end
end)

I’ve looked through other posts but couldn’t find a solution.

2 Likes

Edit: if this doesn’t work, add a check to see if the first 3 pathfind points are behind the NPC, and if they are behind don’t pathfind to it.

1 Like

Thanks, this seems to work a lot better. I’ve noticed a problem though. If im near the NPC, it starts going back and forth. Like it starts walking away, then turning back and walking towards me, then turning aaway and walking away and etc etc. I’ve tried implementing distance checks to stop the NPC from moving within a certain distance, but it just doesn’t work for whatever reason

local function ComputeNewPath(HRP, destination, hum, npc)
	
	CurrentPathsInProgress[npc]=nil
	
	
	local path=PathfindService:CreatePath({
		AgentRadius=2,
		AgentHeight=5,
		AgentCanJump=true,
		AgentJumpHeight=7.5,
		AgentMaxSlope=45,
	})

	path:ComputeAsync(HRP.Position, destination.Position)

	if path.Status==Enum.PathStatus.Success then
	
		CurrentPathsInProgress[npc]=true
		local waypointindex=1
		VisualizePath(path, npc)
		local waypoints=path:GetWaypoints()
		task.spawn(function()
			
			
			local waypoints = path:GetWaypoints()
			local currentWaypointIndex = 1
			local moveDirection = Vector3.new(0, 0, 0)
			local lastPosition = HRP.Position
			local lastUpdate = os.clock()

			local arrivalThreshold = 2
			local stuckThreshold = 0.5
			local moveSpeed = hum.WalkSpeed
			local rotationSpeed = 12

			while currentWaypointIndex <= #waypoints do
				local currentWaypoint = waypoints[currentWaypointIndex]
				local currentPosition = HRP.Position
				local dist=(HRP.Position-destination.Position).Magnitude
				if currentWaypoint.Action == Enum.PathWaypointAction.Jump or hum.Sit == true then
					hum.Jump = true
					task.wait(0.5)
				end

				local toWaypoint = (currentWaypoint.Position - currentPosition) * Vector3.new(1, 0, 1)
				local distance = toWaypoint.Magnitude

				if distance <= arrivalThreshold then
					currentWaypointIndex += 1
					if currentWaypointIndex > #waypoints or dist<=CloseThreshold then break end
					continue
				end

				if os.clock() - lastUpdate > stuckThreshold then
					if (currentPosition - lastPosition).Magnitude < 0.1 then

						return true
					end
					lastPosition = currentPosition
					lastUpdate = os.clock()
				end

				moveDirection = toWaypoint.Unit
				hum:Move(moveDirection)
				
				task.wait()
			end

			hum:Move(Vector3.new(0, 0, 0))
			CurrentPathsInProgress[npc]=nil
			
			return true
		
			
		end)
		
	else
		CurrentPathsInProgress[npc]=nil
		StunnedNPCS[npc]=true
		task.delay(2,function()
			StunnedNPCS[npc]=false
		end)
	end
end

The distance checks also are not desired since this means that they can stun the npc by just staying close to it.

I have broken this problem down to tears. The best I’ve ever been able to get it to work was to have them know the next point before they reach the one they are going to. It’s in that moment of getting the next point to go to that they stutter from time to time.

Yeah the turning back issue is because while the npc is walking the first path point spawns behind it, try to offset the origin based on rootpart linear velocity unit

2 Likes

Yeah, I was having this exact same issue, this fixed it, thank you so much.

1 Like

I’ve figured it out, basically you just need to remove the first waypoint and then it will be all good. Thanks!

2 Likes