Changing NPC position while using pathfindingservice acting weird

  1. What do you want to achieve? A smooth teleportation with the NPC to the player.
  2. What is the issue? Once the script changes the NPC’s position, it starts to “glitch” and the pathfinding doesn’t work after that.
  3. What solutions have you tried so far? Several discord servers & google.

So, I’m basically trying to make a slenderman AI type of system where after a given amount of seconds, it attempts to teleport to a player after chasing the player for a while. The only problem is that when the NPC teleports to the player, it starts to “glitch”, act weird, and the pathfinding path just stops working. I’ve went to several discord servers, but people keep ignoring me and nothing pops up for me on google. Can anyone help me?

-->> VARIABLES <<--
local replicatedStorage,pathFindingService,players = game:GetService('ReplicatedStorage'),game:GetService('PathfindingService'),game:GetService('Players')

local settingsAISettings = replicatedStorage.SlendermanAISettings

local canTeleport,teleportDiff,frontTeleportDiff,teleportEveryMax = settingsAISettings.CanTeleport,settingsAISettings.TeleportDiff,settingsAISettings.FrontTeleportDiff,settingsAISettings.TeleportEveryMax

local slenderman = script:FindFirstAncestorWhichIsA('Model')

local previousDestination

local teleportCooldown,teleportCooldownConnection = 0,nil

local path,waypoints,currentWaypoints = nil,{},0

local teleportWait = false

-->> LOCAL-FUNCTIONS <<--
local function calculateDistance(character: Model)
	return (slenderman.PrimaryPart.Position - character.PrimaryPart.Position).Magnitude
end

local function getClosestPlayer()
	local closestPlayer,distanceRange = nil,math.huge
	for _,player in players:GetPlayers() do
		local character = player.Character or player.CharacterAdded:Wait()
		
		if (character) then
			local calculatedDistance = calculateDistance(character)
			
			if (calculatedDistance < distanceRange) then closestPlayer = character end
		end
	end
	
	return closestPlayer
end

local function planPathToTarget(target)
	local plannedPath: Path = pathFindingService:CreatePath()

	local success,err = pcall(function()
		plannedPath:ComputeAsync(slenderman.PrimaryPart.Position, target.Position)
	end)

	if ((not success) and (err)) then warn(err) return false end

	return plannedPath
end

local function handleTeleportCooldown()
	if (teleportCooldown > 0 or teleportCooldownConnection) then return end

	local randomTeleportCooldownNumber = math.random(0, teleportEveryMax.Value - 15)

	teleportCooldownConnection = coroutine.create(function()
		for i = randomTeleportCooldownNumber, teleportEveryMax.Value, 1 do
			teleportCooldown = i

			task.wait(1)
		end
	end)
	
	coroutine.resume(teleportCooldownConnection)
end

local function walkToDestination(index, closestPlayer)
	if (waypoints[index]) then
		slenderman.Humanoid:MoveTo(waypoints[index].Position)
	else
		previousDestination = closestPlayer
	end
end

local function walkToTarget()
	local function attemptTeleport(character: Model)
		if (not canTeleport.Value) then return end

		handleTeleportCooldown()

		print(teleportCooldown)

		if (teleportCooldown >= teleportEveryMax.Value) then
			local randomTeleportNearNumber,randomFrontTeleportNearNumber = math.random(0, 100),math.random(0, 100)
			
			coroutine.close(teleportCooldownConnection)
			teleportCooldownConnection = nil

			teleportCooldown = 0
			
			if (randomFrontTeleportNearNumber >= frontTeleportDiff.Value) then
				print('FRONT')

				path = nil
				waypoints = {}
				currentWaypoints = 0

				teleportWait = true

				slenderman.Humanoid.WalkToPoint = Vector3.zero
				slenderman.PrimaryPart.Position = character.PrimaryPart.Position + Vector3.new(0, 0, -7)

				task.wait(5)

				teleportWait = false

			elseif (randomTeleportNearNumber >= teleportDiff.Value) then
				print('NEAR')

				path = nil
				waypoints = {}
				currentWaypoints = 0

				teleportWait = true

				slenderman.Humanoid.WalkToPoint = Vector3.zero
				slenderman.PrimaryPart.Position = character.PrimaryPart.Position + Vector3.new(7, 0, 0)

				task.wait(5)

				teleportWait = false
			end
		end
	end
	
	local closestPlayer = getClosestPlayer()
	if (not closestPlayer) then return end
	
	if (not teleportWait) then
		path = planPathToTarget(closestPlayer.PrimaryPart)
		if ((not path) or (path.Status ~= Enum.PathStatus.Success)) then return end

		waypoints,currentWaypoints = path:GetWaypoints()

		path.Blocked:Connect(function()
			closestPlayer = getClosestPlayer()
			path = planPathToTarget(closestPlayer.PrimaryPart)

			waypoints = path:GetWaypoints()
		end)
		
		attemptTeleport(closestPlayer)
		
		walkToDestination(2, closestPlayer)

		for i = 2, #waypoints do
			attemptTeleport(closestPlayer)

			walkToDestination(i, closestPlayer)
		end
	end
end

-->> SCRIPT <<--
slenderman.PrimaryPart:SetNetworkOwner(nil)

while task.wait() do	
	walkToTarget()
end

settings

CanTeleport = true
FrontTeleportDiff = 30
TeleportDiff= 60
TeleportEveryMax = 30

Pathfinding might glitch out after a sudden change of position, and didn’t correctly map out the path for that position, rather the initial position, try reinitializing the pathfinding after the teleport.

add this:

path = planPathToTarget(character.PrimaryPart)

after this [in attemptTeleport() function]:

banner

Think of a way to clear the waypoints table and initiate a Humanoid.MoveToFinished event

Maybe after teleporting, the pathfinding system gets called to again with the teleport endpoint as the goal.

Tweaked the code a little and now I get this result. It can now move forward when walking, but not sideways.

Edit: So, apparently, if the target is in front of the NPC, it walks normally, but if the target is in the side or behind the NPC, then it starts to act glitchy.

You’re onto something here, I just checked and apparently, the waypoints table isn’t clearing.

Edit: Even while I have this code:

path = nil
waypoints = {}
currentWaypoints = 0
1 Like

This post is marked as solved. I did a little more research and found out the solution. Thank you all for helping me.

slenderman:PivotTo(CFrame.new(character.PrimaryPart.Position + Vector3.new(0, -character.PrimaryPart.Position.Y, -7)))
2 Likes

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