Pathfinding ai script does not work

  1. What do you want to achieve?
    I want to make it that normally, the npc uses walkto() to walk to player WITHOUT pathfinding. There is a part that when the npc in in the part, the npc will use pathfinding, and when it is not in the part then it will stop using pathfinding and continue using moveto()

  2. What is the issue? Include screenshots / videos if possible!
    the npc walks to the last point of the player’s location when it walks in the part and stops moving after reaching

  3. What solutions have you tried so far? i asked chatgpt over 5 times​:skull::skull:

game file: ai testing.rbxl (83.4 KB) i promise it is not a virus

local NPCsFolder = game.Workspace.NPCS

local canFollowNPCs = false

local ws = game:GetService("Workspace")
local rs = game:GetService("RunService")
local ts = game:GetService("TweenService")
local pfs = game:GetService("PathfindingService")


local function getNearestTarget(npc, root)
	local dist = 1000
	local char

	if canFollowNPCs == true then
		for _, v in pairs(ws:GetChildren()) do
			if v:FindFirstChild("Humanoid") and v:FindFirstChild("HumanoidRootPart") and v ~= npc then
				local vHum = v:WaitForChild("Humanoid")
				local vRoot = v:WaitForChild("HumanoidRootPart")
				if vHum.Health > 0 then
					local magnitude = (vRoot.Position - root.Position).Magnitude
					if magnitude <= dist then
						dist = magnitude
						char = v
					end
				end
			end
		end
	else
		for _, player in pairs(game.Players:GetPlayers()) do
			local vChar = player.Character
			if vChar and vChar:FindFirstChild("Humanoid") and vChar:FindFirstChild("HumanoidRootPart") then
				local vHum = vChar:WaitForChild("Humanoid")
				local vRoot = vChar:WaitForChild("HumanoidRootPart")
				if vHum.Health > 0 then
					local magnitude = (vRoot.Position - root.Position).Magnitude
					if magnitude <= dist then
						dist = magnitude
						char = vChar
					end
				end
			end
		end
	end
	return char
end







local function handleNPCBehavior(npc)
	local hum = npc:FindFirstChildOfClass("Humanoid")
	local root = npc.HumanoidRootPart

	hum:SetStateEnabled(Enum.HumanoidStateType.Ragdoll, false)
	hum:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding, false)

	local rs = game:GetService("RunService")
	local pfs = game:GetService("PathfindingService")
	local designatedAreasFolder = workspace:WaitForChild("ai_zones")
	local designatedParts = {}

	local usingPathfinding = npc.Configuration.ai.Value
	local path
	local pathUpdateInterval = 0.5  -- Recalculation time interval in seconds

	-- Gather designated parts to be ignored in pathfinding
	for _, part in ipairs(designatedAreasFolder:GetChildren()) do
		if part:IsA("BasePart") then
			table.insert(designatedParts, part)
		end
	end

	-- Set up raycast params to ignore designated parts
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	raycastParams.FilterDescendantsInstances = designatedParts

	-- Check if NPC is inside any designated area part
	local function isInsideAnyPart(position)
		for _, part in ipairs(designatedParts) do
			local size = part.Size
			local partPos = part.Position
			local halfSize = size / 2
			if (position.X > partPos.X - halfSize.X and position.X < partPos.X + halfSize.X) and
				(position.Y > partPos.Y - halfSize.Y and position.Y < partPos.Y + halfSize.Y) and
				(position.Z > partPos.Z - halfSize.Z and position.Z < partPos.Z + halfSize.Z) then
				return true
			end
		end
		return false
	end

	-- Create a path to the target position
	local function createPathToTarget(targetPosition)
		if path then
			path:Destroy()
		end
		path = pfs:CreatePath({
			AgentHeight = hum.HipHeight,
			AgentRadius = 1.6,
			AgentCanJump = true,
			WaypointSpacing = 2,
			FilterParams = raycastParams
		})
		path:ComputeAsync(root.Position, targetPosition)
		return path
	end

	-- Follow the path continuously to the target with recalculations
	local function followPathContinuously(targetRoot)
		while usingPathfinding and path and path.Status == Enum.PathStatus.Complete do
			for _, waypoint in ipairs(path:GetWaypoints()) do
				if not usingPathfinding then break end

				-- Move to each waypoint, updating path periodically
				hum:MoveTo(waypoint.Position)

				-- Wait for either movement or recalculation interval
				local timeout = tick() + pathUpdateInterval
				while hum.MoveToFinished:Wait() == false and tick() < timeout do
					rs.Heartbeat:Wait()
				end

				-- Recalculate path if timeout reached
				if tick() >= timeout then
					path = createPathToTarget(targetRoot.Position)
					break
				end
			end
		end
	end

	-- Main loop to manage pathfinding based on designated area
	rs.Heartbeat:Connect(function()
		if root.Anchored == false then
			root:SetNetworkOwner(nil)
		end

		local target = getNearestTarget(npc, root)

		if target then
			local targetRoot = target:WaitForChild("HumanoidRootPart")
			local insideArea = isInsideAnyPart(root.Position)

			if insideArea then
				-- Start or continue pathfinding if inside area
				if not usingPathfinding then
					usingPathfinding = true
					path = createPathToTarget(targetRoot.Position)
					followPathContinuously(targetRoot)
				end
			else
				-- Outside area: Move directly to player without pathfinding
				usingPathfinding = false
				if path then
					path:Destroy()
					path = nil
				end
				hum:MoveTo(targetRoot.Position)
			end
		end
	end)





end

for _, npc in pairs(NPCsFolder:GetChildren()) do
	if npc:IsA('Model') and npc:FindFirstChildOfClass("Humanoid") then
		handleNPCBehavior(npc)
	end
end

note: i will not be online for now cuz im in skool and im using vpn rn

1 Like

i changed this function

	-- Check if NPC is inside any designated area part
	local function isInsideAnyPart(character)
		for _, part: BasePart in ipairs(designatedParts) do
			local size = part.Size
			local partPos = part.Position
			local halfSize = size / 2
			
			local inPart = workspace:GetPartsInPart(part)
			
			for _, v in pairs(inPart) do
				if v:IsDescendantOf(character) then
					return true
				end
			end
		end
		return false
	end

make sure to give it the npc instead of the root.

2 Likes

wait the npc does not move this error comes up:

Unable to cast value to Object - Server - Script:92

wait i fixed it thx for helping me!

local NPCsFolder = game.Workspace.NPCS

local canFollowNPCs = false

local ws = game:GetService("Workspace")
local rs = game:GetService("RunService")
local ts = game:GetService("TweenService")
local pfs = game:GetService("PathfindingService")

-- Function to get the nearest target (player or NPC)
local function getNearestTarget(npc, root)
	local dist = 1000
	local char

	if canFollowNPCs then
		for _, v in pairs(ws:GetChildren()) do
			if v:FindFirstChild("Humanoid") and v:FindFirstChild("HumanoidRootPart") and v ~= npc then
				local vHum = v:WaitForChild("Humanoid")
				local vRoot = v:WaitForChild("HumanoidRootPart")
				if vHum.Health > 0 then
					local magnitude = (vRoot.Position - root.Position).Magnitude
					if magnitude <= dist then
						dist = magnitude
						char = v
					end
				end
			end
		end
	else
		for _, player in pairs(game.Players:GetPlayers()) do
			local vChar = player.Character
			if vChar and vChar:FindFirstChild("Humanoid") and vChar:FindFirstChild("HumanoidRootPart") then
				local vHum = vChar:WaitForChild("Humanoid")
				local vRoot = vChar:WaitForChild("HumanoidRootPart")
				if vHum.Health > 0 then
					local magnitude = (vRoot.Position - root.Position).Magnitude
					if magnitude <= dist then
						dist = magnitude
						char = vChar
					end
				end
			end
		end
	end
	return char
end

-- Main function to handle NPC behavior
local function handleNPCBehavior(npc)
	local hum = npc:FindFirstChildOfClass("Humanoid")
	local root = npc.HumanoidRootPart

	hum:SetStateEnabled(Enum.HumanoidStateType.Ragdoll, false)
	hum:SetStateEnabled(Enum.HumanoidStateType.PlatformStanding, false)

	local usingPathfinding = npc.Configuration.ai.Value
	local path
	local pathUpdateInterval = 1  -- Recalculation time interval in seconds

	local designatedAreasFolder = workspace:WaitForChild("ai_zones")
	local designatedParts = {}

	-- Gather designated parts to be ignored in pathfinding
	for _, part in ipairs(designatedAreasFolder:GetChildren()) do
		if part:IsA("BasePart") then
			table.insert(designatedParts, part)
		end
	end

	-- Set up raycast params to ignore designated parts
	local raycastParams = RaycastParams.new()
	raycastParams.FilterType = Enum.RaycastFilterType.Blacklist
	raycastParams.FilterDescendantsInstances = designatedParts

	-- Function to check if NPC is inside any designated area part
	local function isInsideAnyPart(character)
		for _, part in ipairs(designatedParts) do
			local partPos = part.Position
			local partSize = part.Size
			local characterPos = character.HumanoidRootPart.Position

			-- Check if the NPC is within the area of the part
			if (partPos - characterPos).Magnitude < (partSize.X / 2) then
				return true
			end
		end
		return false
	end

	-- Create a path to the target position
	local function createPathToTarget(targetPosition)
		-- Debug Output for Path Creation
		print("Creating path to target:", targetPosition)

		if path then
			path:Destroy()
		end

		-- Create a new path using PathfindingService
		path = pfs:CreatePath({
			AgentHeight = hum.HipHeight,
			AgentRadius = 1.6,
			AgentCanJump = true,
			WaypointSpacing = 2,
			FilterParams = raycastParams
		})

		-- Compute the path asynchronously
		path:ComputeAsync(root.Position, targetPosition)
		return path
	end

	-- Function to make the NPC follow the path continuously to the target
	local function followPathContinuously(targetRoot)
		while usingPathfinding do
			-- Create the path to the target
			path = createPathToTarget(targetRoot.Position)

			-- Wait for the path to finish calculating (can add a check if path is ready)
			while path.Status ~= Enum.PathStatus.Success do
				rs.Heartbeat:Wait() -- Wait for path completion
			end

			-- Start moving the NPC towards the target
			for _, waypoint in ipairs(path:GetWaypoints()) do
				hum:MoveTo(waypoint.Position)

				-- Wait for NPC to finish moving to the waypoint
				local success, errorMessage = pcall(function()
					hum.MoveToFinished:Wait()
				end)

				if not success then
					print("Error moving NPC:", errorMessage)
				end
			end

			-- Check if the NPC has arrived at the target and needs to recalculate the path
			local distToTarget = (targetRoot.Position - hum.Parent.HumanoidRootPart.Position).Magnitude
			if distToTarget < 5 then
				print("NPC is close to target, recalculating path.")
				-- Optionally recalculate path after a short time if needed
			end

			-- Recalculate after a timeout if pathfinding was unsuccessful
			wait(pathUpdateInterval)
		end
	end

	-- Main loop for pathfinding
	rs.Heartbeat:Connect(function()
		if root.Anchored == false then
			root:SetNetworkOwner(nil)
		end

		local target = getNearestTarget(npc, root)

		if target then
			local targetRoot = target:WaitForChild("HumanoidRootPart")
			local insideArea = isInsideAnyPart(npc)

			if insideArea then
				-- NPC is inside a designated area, use pathfinding
				if not usingPathfinding then
					usingPathfinding = true
					path = createPathToTarget(targetRoot.Position)
					followPathContinuously(targetRoot)
				end
			else
				-- Outside area: Move directly to player without pathfinding
				usingPathfinding = false
				if path then
					path:Destroy()
					path = nil
				end
				hum:MoveTo(targetRoot.Position)
			end
		end
	end)
end

-- Loop through NPCs in the workspace and start behavior
for _, npc in pairs(NPCsFolder:GetChildren()) do
	if npc:IsA('Model') and npc:FindFirstChildOfClass("Humanoid") then
		handleNPCBehavior(npc)
	end
end

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