Pathfinding/direct movement npc in direct movement mode moves with cuts

Hello, I recently had a problem with a script about an npc pathfinding/direct movement, here is the script with the problem:

local PathfindingService = game:GetService("PathfindingService")
local Players = game:GetService("Players")
local CollectionService = game:GetService("CollectionService")

local zombie = script.Parent
local humanoid = zombie:WaitForChild("Humanoid")
local rootPart = zombie:WaitForChild("HumanoidRootPart")

local ATTACK_DISTANCE = 5
local UPDATE_INTERVAL = 0.5
local RAYCAST_DISTANCE = 20
local JUMP_COOLDOWN = 1
local JUMP_HEIGHT_THRESHOLD = 5
local lastJumpTime = 0
local STUCK_THRESHOLD = 2
local lastPosition = rootPart.Position
local stuckTime = 0

local DAMAGE_AMOUNT = 10
local DAMAGE_COOLDOWN = 2
local lastDamageTime = 0

local path = PathfindingService:CreatePath({
	AgentRadius = 2,
	AgentHeight = 5,
	AgentCanJump = true
})

local attackAnimation = script:WaitForChild("AttackAnimation")
local attackTrack = humanoid:LoadAnimation(attackAnimation)

-- Función para verificar si el zombie está en el suelo
local function isOnGround()
	local rayStart = rootPart.Position
	local rayDirection = Vector3.new(0, -3.1, 0)

	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude
	raycastParams.FilterDescendantsInstances = {zombie}

	local raycastResult = workspace:Raycast(rayStart, rayDirection, raycastParams)
	return raycastResult ~= nil
end

-- Intentar saltar si es necesario
local function tryJump()
	local currentTime = tick()
	if currentTime - lastJumpTime >= JUMP_COOLDOWN and isOnGround() then
		humanoid.Jump = true
		lastJumpTime = currentTime
		return true
	end
	return false
end

-- Buscar al jugador más cercano
local function findNearestPlayer()
	local nearestPlayer = nil
	local shortestDistance = math.huge

	for _, player in ipairs(Players:GetPlayers()) do
		if player.Character and player.Character:FindFirstChild("HumanoidRootPart") and player.Character:FindFirstChild("Humanoid").Health > 0 then
			local distance = (player.Character.HumanoidRootPart.Position - rootPart.Position).Magnitude
			if distance < shortestDistance then
				shortestDistance = distance
				nearestPlayer = player
			end
		end
	end

	return nearestPlayer
end

local function getIgnoreList()
	local ignoreList = {zombie}

	for _, player in ipairs(Players:GetPlayers()) do
		if player.Character then
			table.insert(ignoreList, player.Character)
		end
	end

	for _, npc in ipairs(CollectionService:GetTagged("NPC")) do
		table.insert(ignoreList, npc)
	end

	return ignoreList
end

-- Verificar obstáculos
local function checkObstacles(target)
	local direction = (target.Position - rootPart.Position).Unit

	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Exclude
	raycastParams.FilterDescendantsInstances = getIgnoreList()

	-- Raycast horizontal para obstáculos
	local raycastResult = workspace:Raycast(rootPart.Position, direction * RAYCAST_DISTANCE, raycastParams)

	-- Raycast hacia arriba para detectar obstáculos que podamos saltar
	local upRayStart = rootPart.Position + direction * 2
	local upRaycastResult = workspace:Raycast(upRayStart, Vector3.new(0, 4, 0), raycastParams)

	if raycastResult then
		local hitPart = raycastResult.Instance

		if hitPart.CanCollide then
			-- Verificar si podemos saltar sobre el obstáculo
			local obstacleHeight = (raycastResult.Position.Y - rootPart.Position.Y)

			if obstacleHeight > 0 and obstacleHeight < JUMP_HEIGHT_THRESHOLD and not upRaycastResult then
				-- Intentar saltar si el obstáculo no es muy alto
				if tryJump() then
					return false
				end
			end
			return true
		end
	end

	return false
end

-- Función para infligir daño al jugador
local function attackPlayer(player)
	local currentTime = tick()
	if currentTime - lastDamageTime >= DAMAGE_COOLDOWN then
		local humanoidTarget = player.Character:FindFirstChild("Humanoid")
		if humanoidTarget and humanoidTarget.Health > 0 then
			attackTrack:Play() -- Reproducir animación de ataque
			humanoidTarget:TakeDamage(DAMAGE_AMOUNT)
			lastDamageTime = currentTime
		end
	end
end

-- Verificar si el zombie está atascado
local function checkStuck()
	local currentPosition = rootPart.Position
	if (currentPosition - lastPosition).Magnitude < 1 then
		stuckTime = stuckTime + UPDATE_INTERVAL
		if stuckTime >= STUCK_THRESHOLD then
			return true
		end
	else
		stuckTime = 0
	end
	lastPosition = currentPosition
	return false
end

-- Movimiento directo hacia el jugador
local function moveDirectlyToTarget(target)
	local targetPosition = target.Position
	humanoid:MoveTo(targetPosition)
end

-- Movimiento con recalculo de camino si está atascado u obstaculizado
local function followPathToTarget(target)
	local success, errorMessage = pcall(function()
		path:ComputeAsync(rootPart.Position, target.Position)
	end)

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

		for _, waypoint in ipairs(waypoints) do
			if humanoid.Health <= 0 then
				break
			end

			if waypoint.Action == Enum.PathWaypointAction.Jump then
				tryJump()
			end

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

-- Función principal para el movimiento del zombie
local function updateZombieMovement()
	while humanoid.Health > 0 do
		local nearestPlayer = findNearestPlayer()

		if nearestPlayer and nearestPlayer.Character then
			local targetRoot = nearestPlayer.Character:FindFirstChild("HumanoidRootPart")

			if targetRoot then
				local distance = (targetRoot.Position - rootPart.Position).Magnitude

				if distance <= ATTACK_DISTANCE then
					humanoid:MoveTo(rootPart.Position) -- Detenerse
					attackPlayer(nearestPlayer)
				else
					local heightDifference = math.abs(targetRoot.Position.Y - rootPart.Position.Y)
					local hasObstacles = checkObstacles(targetRoot)
					local isStuck = checkStuck()

					if isStuck or heightDifference > JUMP_HEIGHT_THRESHOLD or hasObstacles then
						followPathToTarget(targetRoot) -- Recalcular si hay obstáculos
					else
						moveDirectlyToTarget(targetRoot) -- Seguir directamente si no hay obstáculos
					end
				end
			end
		end

		wait(UPDATE_INTERVAL)
	end

	humanoid:MoveTo(rootPart.Position)
end

updateZombieMovement()

Heres a video of the Problem:

This is because the AI has to re-path each time it gets to its goal, and because its trying to follow a player that moving. It doesn’t re-path its goal to the new position of the player until the current path is finished.