NPC slowing down when close to the player

I’ve been trying to make an NPC that chases the player, but I came across this bug that I can’t fix.

When the NPC is within a 5-ish stud range of the player, they start to stutter, matching the player’s walking speed (12 studs/s) even though the NPC is faster (21 studs/s), does anybody know how to fix this?

Here’s the script:

local PathFindingService = game:GetService("PathfindingService")
local RunService = game:GetService("RunService")

local humanoid = script.Parent.Humanoid
local rootPart = script.Parent.HumanoidRootPart

pcall(function()
	script.Parent.PrimaryPart:SetNetworkOwner(nil)
end)

local updateTime = 0.1
local moving = false

local newPath = PathFindingService:CreatePath(
	{
		AgentRadius = 2.1,
		AgentHeight = 5,
		AgentCanJump = false,
		AgentCanClimb = false,
		WaypointSpacing = 4
	}
)

local currentTarget = nil

local function FindTarget()
	local targetDistance = math.huge
	local targetRootPart = nil
	local targetPlayer = nil

	for i, v in pairs(game.Players:GetPlayers()) do
		if v.Character then
			local playerHumanoid = v.Character:FindFirstChildOfClass("Humanoid")
			local playerRootPart = playerHumanoid.RootPart

			if playerHumanoid and playerRootPart then
				local distance = (playerRootPart.Position - rootPart.Position).Magnitude
				if distance > 0 and distance < targetDistance then
					targetDistance = distance
					targetRootPart = playerRootPart
				end
			end
		end
	end

	return targetRootPart
end

local success, errorMsg

task.spawn(function()
	local target = FindTarget()
	if target then
		success, errorMsg = pcall(function()
			newPath:ComputeAsync(rootPart.Position, target.Position)
		end)
	end
end)

RunService.Heartbeat:Connect(function(delta)
	if not moving then
		moving = true
		
		local target = FindTarget()
		if target then
			if success and newPath.Status == Enum.PathStatus.Success then
				local waypoints = newPath:GetWaypoints()
				if waypoints[2] then
					currentTarget = waypoints[2].Position
					
					task.spawn(function()
						success, errorMsg = pcall(function()
							newPath:ComputeAsync(waypoints[2].Position, target.Position)
						end)
					end)
				else
					currentTarget = nil
				end
			else
				currentTarget = nil
			end
		else
			currentTarget = nil
		end
		
		task.spawn(function()
			if currentTarget then
				humanoid:MoveTo(currentTarget)
			else
				success, errorMsg = pcall(function()
					newPath:ComputeAsync(rootPart.Position, target.Position)
				end)

				humanoid:MoveTo(rootPart.Position)
			end
		end)
		
		humanoid.MoveToFinished:Connect(function()
			moving = false
		end)
	end
end)
1 Like

try setting the npc’s network authority to the server

pcall(function()
	script.Parent.PrimaryPart:SetNetworkOwner(nil)
end)

already did

1 Like

try setting the npc’s network authority to the server though

oh sorry i thought you meant owership

it didnt work, do you know about any other solution?

instead of giving NPC your raw root part position, you could add a velocity to make a prediction of where your character is at, u gotta adjust it to be based on speed to get the right one

formula for it isn’t hard, u just need the direction vector then multiply with the speed of the target character, though this isn’t perfect but atleast it’ll be able to catch up with the target

my approach was later switched to “RemoteFunction” that gives the actual position from client then invokes to a server immediately (this one isn’t safe if you have the actual remote function but i had a library that replaces this)

1 Like

Assuming you’re processing the NPC logic on the server, this happens because the server side reports your character as being much closer to the NPC than it looks client-side.
As a result, it’ll constantly overlap with the target position, stopping, before continuing because the server updated the character position to be ahead again.

This is just the byproduct of latency that you need to account for.

As @pankii_kust mentioned, you can fix this by making the NPC target past the character’s location, by predicting where they go according to their current velocity.

The idea is simple:
Take the target position and add a variable amount of velocity into the direction they are moving.
The velocity can be a predefined constant, or better, calculated based on the target character’s ping.
The resulting vector will be your NPC’s actual target position it should move towards.

3 Likes

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.