Why is this character pausing while moving?

So for some reason, when you make the character’s speed higher(or change the speed mid movement) it does this weird pausing thing?

The activate just makes the npc activate an ability that lasts for 3 seconds, making the walkspeed 25.

local CS = game:GetService("CollectionService")
local Pathfind = game:GetService("PathfindingService")

local attacktag = "Prey"

function isprey(part)
	return CS:HasTag(part, attacktag)
end

while task.wait(0.1) do
	local human = script.Parent.Humanoid
	local pos = human.RootPart.Position
	local target = nil
	local targetDistance = math.huge
	local path = Pathfind:CreatePath({["WaypointSpacing"] = 32})
	local op = OverlapParams.new()
	op.FilterType = Enum.RaycastFilterType.Exclude
	op.FilterDescendantsInstances = {script.Parent}

	for _, i in workspace:GetPartBoundsInRadius(pos, 1000, op) do
		if isprey(i) then
			if (i.Position-pos).Magnitude < targetDistance then
				path:ComputeAsync(pos, i.Position)
				if path.Status == Enum.PathStatus.Success then
					target = i.Position
					targetDistance = (i.Position-pos).Magnitude
				end
			end
		end
	end

	if target then
		path:ComputeAsync(pos, target)
		local waypoint = path:GetWaypoints()[2]
		human:MoveTo(waypoint.Position)
	end
end
1 Like

I believe this is because the zombie is getting your position on the server, which is a bit delayed, making the script think the zombie is touching you, it “pauses” because of the collisions of your character, it’s pretty much like walking into a wall. I’m not sure this is the reason why though.

You can try to look on the server side how it looks like (click on the Test tab and click on Start on the “Clients and Servers” section".

Sorry if I didn’t explain it well.


That’s on the client

And on the server it looks much more different

image

Why would this be happening, I tried setting the network owner to the server too

Might not be the issue, but try setting the HumanoidRootPart’s network owner to the server to prevent clients from taking over:

script.Parent.HumanoidRootPart:SetNetworkOwner()
1 Like

Actually, I think it’s because you’re only using one of the computed waypoints, meaning that it has to constantly wait for a new computation before moving again.
You should change it to go through all waypoints and refresh them in the background.

Alternatively you could also make it blindly move towards your target while it’s computing a path.

1 Like

They do that when they reach the waypoint and then hit a pause before the next waypoint is known or if the pause overlaps. It’s all about the timing vs your spacing.

Nice tight little NPC script. I wonder what a task.wait(0.033) would do here vs 0.1 …
I’d sure mess around with that number a bit as close as this is now.

That wouldn’t change much as computing a path itself isn’t instantaneous and yields.

Looks like it’s stopping to attack…
I actually thought that was a task.wait(1) … 0.1 should be good.
I just know that is a fine balance to get that not to pause like that.
The ones I made took a lot of playing around to find the right balance.

It doesn’t stop to attack, it just deals damage

Hey, the pausing happens because you’re recalculating the path way too often and not handling the waypoints properly. You’re calling ComputeAsync multiple times per loop, which basically makes the NPC stop and rethink its route constantly. Also, you’re trying to move to a whole list of waypoints at once instead of going through them one by one.

Here’s a cleaner way to do it: find your target first, compute the path once, then move through each waypoint in order, waiting until the NPC reaches each point before moving on. That should stop the pausing.

Check this out:

local CS = game:GetService("CollectionService")
local PathfindingService = game:GetService("PathfindingService")
local attackTag = "Prey"

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

function isPrey(part)
    return CS:HasTag(part, attackTag)
end

while task.wait(0.1) do
    local position = rootPart.Position
    local target = nil
    local closestDistance = math.huge

    local overlapParams = OverlapParams.new()
    overlapParams.FilterType = Enum.RaycastFilterType.Exclude
    overlapParams.FilterDescendantsInstances = {script.Parent}

    for _, part in workspace:GetPartBoundsInRadius(position, 1000, overlapParams) do
        if isPrey(part) then
            local dist = (part.Position - position).Magnitude
            if dist < closestDistance then
                target = part.Position
                closestDistance = dist
            end
        end
    end

    if target then
        local path = PathfindingService:CreatePath({WaypointSpacing = 32})
        path:ComputeAsync(position, target)

        if path.Status == Enum.PathStatus.Success then
            local waypoints = path:GetWaypoints()

            for _, waypoint in ipairs(waypoints) do
                humanoid:MoveTo(waypoint.Position)
                local reached = humanoid.MoveToFinished:Wait()
                if not reached then
                    break -- stop if path is blocked
                end
            end
        end
    end
end

Try that and see if it smooths things out. If you’re still stuck, maybe rethink how often you’re changing walk speed or interrupting movement.

I tried to set the npc’s baseparts network owner to the player too and use your script but it didn’t work.

The only lead I have is the fact it’s on a different position in the server but network owner is the only thing that solves that and even that didn’t work. I don’t interrupt movement at all, what’s going on.

i had a NPC system of mine that fixes this a long time ago, like everyone said already, it’s already reached to the target and the server already sees that but it happens cuz it’s also looking at the client side pos of the target, no matter if u set network owner to nil, it’ll still happen occasionally until you stopped

one of the naïve solution was to, add velocity of where the target is moving, this works but, it could be far or that even if it was already reaching the target by 2 studs, you can also dodge them easily by zig-zagging so it can’t rlly catch

what i did was basically using RemoteFunctions that return the actual client position instead of server by invoking the pos of the target, the difference is that now NPC will be able to catch the character, though a side note here while Remote functions aren’t typically recommended cuz of how exploitable it is, someone already made another function that uses remote event, works the same way as remote functions but rn the way it works is kind of a troublemaker

here’s after i applied the second fix ignore the hitbox miss, i swapped to magnitude and it managed to hit me

and before

pathfinding at close range is always choppy and unnecessary

at close range, you should make a raycast to the player character and pathfind if its blocked, otherwise just call :MoveTo directly to the character position

Nope, I tried to use a remote function to send the player’s character’s position, it made it even worse.

Now the enemy starts jittering when it’s close to me

If the NPC is on a different position on the server and you’re trying to set network ownership to a player, that won’t fix pathfinding pauses caused by server-side movement logic. Network ownership mainly affects physics simulation and client-side prediction, but pathfinding and Humanoid:MoveTo run on the server.

Make sure your pathfinding and movement code runs only on the server and that the NPC’s position is consistent there. If the NPC’s position is out of sync between server and client, that can cause weird movement behavior.

Also, check if any other scripts or constraints are affecting the NPC’s Humanoid or RootPart movement. Sometimes collisions, anchored parts, or conflicting scripts cause pauses.

If you want, try adding debug prints to confirm the NPC’s position and path status on the server each step, and verify that MoveToFinished events are firing as expected.