Entity keeps turning around

  1. What do you want to achieve? Keep it simple and clear!
    i need to fix an entity for my game (it keeps turning around)
  2. What is the issue? Include screenshots / videos if possible!
    my entity keeps turning around, most likely due to skipping a waypoint during the walking part
  3. What solutions have you tried so far? Did you look for solutions on the Creator Hub?
    i have looked and have not found anything so far, tho i know its most likely skipping a waypoint during a turn, causing it to turn around to get it again.
				local agentParams = {
					AgentRadius = 4;
					AgentHeight = 10;
					AgentCanJump = false;
				}
				local path = pathfindingservice:CreatePath(agentParams)
				
				local success, error = pcall(function()
					path:ComputeAsync(entity.PrimaryPart.Position, part.Position)
				end)
				local waypoints = path:GetWaypoints()
				if success and path.Status == Enum.PathStatus.Success then
					for _,waypoint in pairs(path:GetWaypoints()) do
						local part = Instance.new("Part")
						part.Size = Vector3.new(1,1,1)
						part.Position = waypoint.Position
						part.Parent = game.Workspace
						part.Anchored = true
						part.BrickColor = BrickColor.new("Really red")
						part.CanCollide = false
						part.Material = Enum.Material.Neon
						entity.Humanoid:MoveTo(waypoint.Position)
						entity.Humanoid.MoveToFinished:Wait()
					end
				else
					warn("error")
				end
2 Likes

for specification, im using a custom rig, it manages to slide past a waypoint and forces itself to turn around, it ALSO does this when i turn of auto rotate, i adjusted the hipheight too.


i made an image showing how it slips, how do i stop that???

crazy take, but check if the path is getting blocked, other factors to include could be the axis it’s on just not reading the path correctly - make the start TO end point in a straight line for the path and see if it computes. In workspace there’s a setting that can improve the search, HERE explains it.

its not that the path is wrong or anything (it works fine with a normal npc) but as i use an custom rig it starts slipping so its specific to that not to the path itself

Increase AgentRadius or append WaypointSpacing to the agentParams table then set the value higher than 4

it works somewhat, with removing the buggyness, still doesnt make it turn instantly like the way the normal npc’s do it (which i’d prefer)

Why dont ya grab the direction of the current waypoint to the next then just manually turn the custom rig?

Just get the next waypoint by adding 1 to the index then grab the next index’s waypoint position then get the direction on your own to adjust the rotation of the rig on your own!

i tried and couldnt get it to work (and it still worked the same after i got it to work)

Alright, I looked into this, and the likely issue is that, for one, MoveToFinished is fairly unreliable because it can work in the future and use predictions. So, as a replacement (as seen here), many developers just use Heartbeat logic to perform waypoint actions. (You can also see people struggling with MoveTo logic here).

I’d recommend using RenderStepped/Heartbeat logic for your problem, and I’d implement it similar to this (you should just be able to replace your loop with this).

local RunService = game:GetService("RunService")
local Debris = game:GetService("Debris")

local agentParams = {
    AgentRadius = 4;
    AgentHeight = 10;
    AgentCanJump = false;
}
local path = pathfindingservice:CreatePath(agentParams)

local function followToDestination(entity, part)
    if not entity or not entity.PrimaryPart or not part then return false end

    while true do
        local success, error = pcall(function()
            path:ComputeAsync(entity.PrimaryPart.Position, part.Position)
        end)

        if not success or path.Status ~= Enum.PathStatus.Success then
            warn("Path compute failed:", error, path.Status)
            return false
        end

        local waypoints = path:GetWaypoints()
        if #waypoints == 0 then
            warn("No waypoints returned")
            return false
        end

        local finalPos = waypoints[#waypoints].Position
        if (entity.PrimaryPart.Position - finalPos).Magnitude <= 1.0 then
            return true
        end

        local blocked = false
        local blockedConn
        blockedConn = path.Blocked:Connect(function(blockedIndex)
            blocked = true
            if blockedConn and blockedConn.Connected then blockedConn:Disconnect() end
        end)

        local humanoid = entity:FindFirstChildOfClass("Humanoid")
        local root = entity.PrimaryPart
        if not humanoid or not root then
            if blockedConn and blockedConn.Connected then blockedConn:Disconnect() end
            warn("Missing humanoid or PrimaryPart")
            return false
        end

        local reachedAll = true
        for i = 1, #waypoints do
            local waypoint = waypoints[i]

            local debugPart = Instance.new("Part")
            debugPart.Size = Vector3.new(1,1,1)
            debugPart.Position = waypoint.Position
            debugPart.Parent = game.Workspace
            debugPart.Anchored = true
            debugPart.BrickColor = BrickColor.new("Really red")
            debugPart.CanCollide = false
            debugPart.Material = Enum.Material.Neon
            Debris:AddItem(debugPart, 5)

            humanoid:MoveTo(waypoint.Position)

            local v = math.max(humanoid.WalkSpeed or 16, 0.1)
            local a = 20
            local d_stop = (v * v) / (2 * a)
            local safety_margin = 1.5
            local threshold = math.max(0.8, d_stop + safety_margin)

            local D = (root.Position - waypoint.Position).Magnitude

            local t_ideal = D / v
            local beta = 1.4
            local t_min = 0.35
            local timeout = math.max(t_min, beta * t_ideal + 0.25)

            timeout = math.min(timeout, 6)

            local reached = false
            local startTime = tick()
            while tick() - startTime < timeout do
                local curDist = (root.Position - waypoint.Position).Magnitude
                if curDist <= threshold then
                    reached = true
                    break
                end

                if curDist <= d_stop + safety_margin * 1.2 then
                    local extraWaitStart = tick()
                    while tick() - extraWaitStart < 0.25 do
                        if (root.Position - waypoint.Position).Magnitude <= threshold then
                            reached = true
                            break
                        end
                        RunService.Heartbeat:Wait()
                    end
                    if reached then break end
                end

                if blocked then break end

                RunService.Heartbeat:Wait()
            end

            if not reached or blocked then
                reachedAll = false
                break
            end
        end

        if blockedConn and blockedConn.Connected then blockedConn:Disconnect() end

        if reachedAll then
            local finalWaypointPos = waypoints[#waypoints].Position
            if (entity.PrimaryPart.Position - finalWaypointPos).Magnitude <= math.max(1.0, (humanoid.WalkSpeed or 16) * 0.2) then
                return true
            end
        end

        wait(0.1)
    end
end

If you need a further explanation, this uses some kinematics such as 𝑑_stop = 𝑣^2/2𝑎, which computes the stopping distance, 𝑡_ideal = 𝐷/𝑣 which multiplies the timeout by 𝛽 and a small margin. Furthermore, I used a few numbers to get the best results.

  • a = 20 (studs/s^2), which stops the script from overestimating the distance
  • safety_margin = 1.5 which covers the jitter, and prevents the NPC from going astray
  • beta = 1.4 which gives small but responsive and tolerant updates

I tried to account for everything, such as measuring the distance between the waypoints, preventing the code from oscillating when met with obstacles instead of oscillating, and making sure nothing overrides each other. Let me know if this works.

The issue you’re describing is classic pathfinding behavior—your entity is likely overshooting waypoints due to movement speed or turning radius not being properly calibrated to the pathfinding grid.Here’s what’s happening: when your entity moves at a certain speed, it can overshoot a waypoint slightly. On turns, this causes the pathfinding to recalculate, and the entity snaps back to chase the skipped waypoint, creating that spinning behavior.**Fix this with these steps:**1. Increase your AgentRadius — You’re using 4, which is quite small. Try bumping it to 6-8. This gives pathfinding more buffer space when computing turns and prevents tight corner overshoots.2. Implement waypoint proximity checks — Don’t just move toward waypoints blindly:lualocal WAYPOINT_THRESHOLD = 5 -- Adjust based on your entity speedif (entity.PrimaryPart.Position - waypoint.Position).Magnitude < WAYPOINT_THRESHOLD then -- Move to next waypoint instead of overshootingend3. Reduce turning speed — If your entity rotates instantly, it can’t follow the path smoothly. Implement gradual rotation:lualocal targetCFrame = CFrame.lookAt(entity.PrimaryPart.Position, waypoint.Position)entity.PrimaryPart.CFrame = entity.PrimaryPart.CFrame:Lerp(targetCFrame, 0.1) -- Adjust 0.1 for smoother/snappier turns4. Check Action types — You’re probably not handling Enum.PathWaypointAction.Jump. Make sure you’re checking waypoint actions and pausing movement appropriately.5. Visualize your path — Keep those debug parts you’re creating. It’ll show if waypoints are being skipped or if your entity’s collision box is too large.Test with AgentRadius = 6 and WAYPOINT_THRESHOLD = 5 first—that solves most spinning issues I’ve seen.

not sure if this is right but using pairs means it doesn’t go in order but ipairs goes in order so try using ipairs. but i recommend to just not use pairs or ipairs since luau will automatically choose the best option sooo:

for _,waypoint in path:GetWaypoints() do

it does go in order i already tested this.