How to fix pathfinding stuck in a specific location

Im working on a game, and I have an issue with an NPC system. When a player buys an NPC, its supposed to walk to the base, but it gets stuck at a specific location. Im aware that the code is quite messy and poorly written. Could someone
please help me fix this?

	local function moveToPlayerBase(player, PersonMut, PersonAddMut)
		if not player or not Person or not Person.Parent then return end

		if playerLeftConnection then
			playerLeftConnection:Disconnect()
		end
		
		if playerGoBackConnection then
			playerGoBackConnection:Disconnect()
		end
		playerLeftConnection = game.Players.PlayerRemoving:Connect(function(leftPlayer)
			if leftPlayer == currentBuyer and isMovingToBase then
				if UnoccupiedSlot then
					UnoccupiedSlot.Configuration.Occupied.Value = false
				end
				moveToExit()
				playerLeftConnection:Disconnect()
			end
		end)
		
		playerGoBackConnection = game.ReplicatedStorage.Events.GoBackMazafaka.Event:Connect(function(goBackPlayer)
			if goBackPlayer == currentBuyer and isMovingToBase then
				if UnoccupiedSlot then
					UnoccupiedSlot.Configuration.Occupied.Value = false
				end
				moveToExit()
				playerGoBackConnection:Disconnect()
			end
		end)

		shouldStopMoving = true
		if moveConnection then
			moveConnection:Disconnect()
			moveConnection = nil
		end
		people.StopPerson(Person)
		shouldStopMoving = false

		local humanoid = Person:FindFirstChildOfClass("Humanoid")
		local rootPart = Person:FindFirstChild("HumanoidRootPart")
		if not humanoid or not rootPart then return end

		local playerBase = workspace:WaitForChild("Bases"):FindFirstChild(player.Name)
		if not playerBase then 
			moveToExit()
			return 
		end

		local targetPart = playerBase:WaitForChild("CollectZone")
		if not targetPart then 
			moveToExit()
			return 
		end

		local waypoints

		if not waypoints then
			local pathfindingService = game:GetService("PathfindingService")
			local path = pathfindingService:CreatePath(PATHFINDING_PARAMS)

			local success, errorMessage = pcall(function()
				path:ComputeAsync(rootPart.Position, targetPart.Position)
			end)

			if not success then
				warn("Path computation error:", errorMessage)
				
				return
			end

			if path.Status == Enum.PathStatus.Success then
				waypoints = path:GetWaypoints()
				
				for i, waypoint in ipairs(waypoints) do
					local part = Instance.new("Part")
					part.Size = Vector3.new(1, 1, 1)
					part.Position = waypoint.Position + Vector3.new(0, 1, 0)
					part.Anchored = true
					part.CanCollide = false
					part.Color = Color3.fromRGB(255, 0, 0)
					part.Material = Enum.Material.Neon
					part.Name = "Waypoint_" .. i
					part.Parent = workspace
				end
			else
				warn("Path not found to player base. Status:", path.Status)
				Person:SetPrimaryPartCFrame(targetPart.CFrame * CFrame.new(0, 0, -2))

				isMovingToBase = false
				updatePrompt()

				if playerLeftConnection then
					playerLeftConnection:Disconnect()
					playerLeftConnection = nil
				end

				local playerProfile = PlayerData.GetProfile(player)
				if playerProfile then
					Person:Destroy()
					PlayerData.AddPeople(player, Person.Name, PersonMut, PersonAddMut, UnoccupiedSlot.Name)
					people.AddPerson(player, Person.Name, PersonMut, PersonAddMut, UnoccupiedSlot.Name)
				end
				return
			end
		end

		local pathWaypointIndex = 1

		local function followNewPath()
			if shouldStopMoving or not Person or not Person.Parent then 
				return
			end

			if pathWaypointIndex > #waypoints then
				isMovingToBase = false
				updatePrompt()

				if playerLeftConnection then
					playerLeftConnection:Disconnect()
					playerLeftConnection = nil
				end

				local playerProfile = PlayerData.GetProfile(player)
				if playerProfile and Person and Person.Parent then
					PlayerData.AddPeople(player, Person.Name, PersonMut, PersonAddMut, UnoccupiedSlot.Name)
					Person:Destroy()
					people.AddPerson(player, Person.Name, PersonMut, PersonAddMut, UnoccupiedSlot.Name)
				end
				return
			end

			local waypoint = waypoints[pathWaypointIndex]
			
			for i, waypoint in ipairs(waypoints) do
				local part = Instance.new("Part")
				part.Size = Vector3.new(1, 1, 1)
				part.Position = waypoint.Position + Vector3.new(0, 1, 0) -- чуть выше земли
				part.Anchored = true
				part.CanCollide = false
				part.Color = Color3.fromRGB(255, 0, 0)
				part.Material = Enum.Material.Neon
				part.Name = "Waypoint_" .. i
				part.Parent = workspace
			end

			if waypoint.Action == Enum.PathWaypointAction.Jump then
				humanoid.Jump = true
			end

			humanoid:MoveTo(waypoint.Position)

			moveConnection = humanoid.MoveToFinished:Connect(function(reached)
				if not reached or shouldStopMoving or not Person or not Person.Parent then
					if moveConnection then
						moveConnection:Disconnect()
						moveConnection = nil
					end
					return
				end

				pathWaypointIndex = pathWaypointIndex + 1
				if moveConnection then
					moveConnection:Disconnect()
					moveConnection = nil
				end
				followNewPath()
			end)
		end

		followNewPath()
	end

Hmm, looks like it’s blocked. I see no path recalculation here when not moving correctly, so:

local function moveToPlayerBase(player, PersonMut, PersonAddMut)
	if not player or not Person or not Person.Parent then return end

	if playerLeftConnection then playerLeftConnection:Disconnect() end
	if playerGoBackConnection then playerGoBackConnection:Disconnect() end

	playerLeftConnection = game.Players.PlayerRemoving:Connect(function(leftPlayer)
		if leftPlayer == currentBuyer and isMovingToBase then
			if UnoccupiedSlot then UnoccupiedSlot.Configuration.Occupied.Value = false end
			moveToExit()
			playerLeftConnection:Disconnect()
		end
	end)

	playerGoBackConnection = game.ReplicatedStorage.Events.GoBackMazafaka.Event:Connect(function(goBackPlayer)
		if goBackPlayer == currentBuyer and isMovingToBase then
			if UnoccupiedSlot then UnoccupiedSlot.Configuration.Occupied.Value = false end
			moveToExit()
			playerGoBackConnection:Disconnect()
		end
	end)

	shouldStopMoving = true
	if moveConnection then moveConnection:Disconnect() moveConnection = nil end
	people.StopPerson(Person)
	shouldStopMoving = false

	local humanoid = Person:FindFirstChildOfClass("Humanoid")
	local rootPart = Person:FindFirstChild("HumanoidRootPart")
	if not humanoid or not rootPart then return end

	local playerBase = workspace:WaitForChild("Bases"):FindFirstChild(player.Name)
	if not playerBase then moveToExit() return end
	local targetPart = playerBase:WaitForChild("CollectZone")
	if not targetPart then moveToExit() return end

	local pathfindingService = game:GetService("PathfindingService")
	local path = pathfindingService:CreatePath(PATHFINDING_PARAMS)
	local ok, err = pcall(function() path:ComputeAsync(rootPart.Position, targetPart.Position) end)
	if not ok or path.Status ~= Enum.PathStatus.Success then
		Person:SetPrimaryPartCFrame(targetPart.CFrame * CFrame.new(0, 0, -2))
		isMovingToBase = false
		updatePrompt()
		if playerLeftConnection then playerLeftConnection:Disconnect() playerLeftConnection = nil end
		local playerProfile = PlayerData.GetProfile(player)
		if playerProfile then
			Person:Destroy()
			PlayerData.AddPeople(player, Person.Name, PersonMut, PersonAddMut, UnoccupiedSlot.Name)
			people.AddPerson(player, Person.Name, PersonMut, PersonAddMut, UnoccupiedSlot.Name)
		end
		return
	end

	local waypoints = path:GetWaypoints()
	local pathWaypointIndex = 1

	local function followNewPath()
		if shouldStopMoving or not Person or not Person.Parent then return end
		if pathWaypointIndex > #waypoints then
			isMovingToBase = false
			updatePrompt()
			if playerLeftConnection then playerLeftConnection:Disconnect() playerLeftConnection = nil end
			local playerProfile = PlayerData.GetProfile(player)
			if playerProfile and Person and Person.Parent then
				PlayerData.AddPeople(player, Person.Name, PersonMut, PersonAddMut, UnoccupiedSlot.Name)
				Person:Destroy()
				people.AddPerson(player, Person.Name, PersonMut, PersonAddMut, UnoccupiedSlot.Name)
			end
			return
		end

		local waypoint = waypoints[pathWaypointIndex]
		if waypoint.Action == Enum.PathWaypointAction.Jump then humanoid.Jump = true end
		local beforePos = rootPart.Position
		humanoid:MoveTo(waypoint.Position)
		if moveConnection then moveConnection:Disconnect() moveConnection = nil end

		moveConnection = humanoid.MoveToFinished:Connect(function(reached)
			if shouldStopMoving or not Person or not Person.Parent then
				if moveConnection then moveConnection:Disconnect() moveConnection = nil end
				return
			end

			local moved = (rootPart.Position - beforePos).Magnitude > 0.5
			if not reached or not moved then
				local newPath = pathfindingService:CreatePath(PATHFINDING_PARAMS)
				local ok2, err2 = pcall(function() newPath:ComputeAsync(rootPart.Position, targetPart.Position) end)
				if ok2 and newPath.Status == Enum.PathStatus.Success then
					waypoints = newPath:GetWaypoints()
					pathWaypointIndex = 1
					if moveConnection then moveConnection:Disconnect() moveConnection = nil end
					followNewPath()
					return
				end
				Person:SetPrimaryPartCFrame(CFrame.new(waypoint.Position + Vector3.new(0, 2, 0)))
				task.wait(0.05)
				pathWaypointIndex = pathWaypointIndex + 1
				if moveConnection then moveConnection:Disconnect() moveConnection = nil end
				followNewPath()
				return
			end

			pathWaypointIndex = pathWaypointIndex + 1
			if moveConnection then moveConnection:Disconnect() moveConnection = nil end
			followNewPath()
		end)
	end

	followNewPath()
end

I tried your script, but when I purchase the NPCs, they just stop and dont move anywhere

Lol, guessing will do that. Check out the recalculation part and reconstruct it. It really looks like it’s being blocked however.. Everything is moving too well to just suddenly stop there.

1 Like

Hmm… I dont really know much about pathfinding. Could you explain how it works?

That player running around like that is killing me.. That’s just too funny. You’re going to have to trouble shoot this one to death. I’m at al loss here.

you can try use SimplePath module.

3 Likes

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