Pathfinding broken [NEEDS TO BE FIXED]

I have an npc that should go to random waypoints, and after each waypoint, it goes to a new one.

However, it keeps trying to go to all of the waypoints at once.

script:



local npc = script.Parent
local human = npc.Humanoid
local hrp = npc:WaitForChild("HumanoidRootPart")

local PFS = game:GetService("PathfindingService")
local RUNSERVICE = game:GetService("RunService")

local destination = workspace.CampingPath:GetChildren()

ues.EnableCamping.Changed:Wait()


npc.PrimaryPart:SetNetworkOwner(nil)

local points = {}
for _,part in ipairs(destination) do
	table.insert(points,part)
	task.wait()
end



function walkRandomly()
	--IsAttacking.Value = false
	local point = points[math.random(1,#points)]
	--local target = FindTarget()
	local path = game:GetService("PathfindingService"):CreatePath({
		AgentRadius = 2,
		AgentHeight = 5,
		AgentCanJump = true,
		Costs = {
			PathFindingModifier = math.huge
		}
	})
	path.Blocked:Connect(function()
		path:Destroy()
		print("DEBUG: PATH BLOCKED (WALKRANDOMLY)")
		walkRandomly()
	end)
	path:ComputeAsync(hrp.Position, point.Position)

	local waypoints = path:GetWaypoints()
	for _, waypoint in ipairs(waypoints) do
		if foundtarget == nil then
			--print("DEBUG: WALKING RANDOMLY TO WAYPOINT")
			--IsAttacking.Value = false
			human:MoveTo(waypoint.Position)
			IsAttacking.Value = false
			foundtarget = nil
			human.WalkSpeed = 8
			path.Blocked:Connect(function()
				path:Destroy()
				print("DEBUG: PATH BLOCKED (WALKRANDOMLY)")
				walkRandomly()
			end)
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				human:ChangeState(Enum.HumanoidStateType.Jumping)
			end
		end
		if IsAttacking.Value then path:Destroy() break end
		human.MoveToFinished:Wait()
		--FindTarget()
	end

end


local Swings = 0

local function findTarget()
	--print('should run every frame 2')
	local players = game:GetService("Players"):GetPlayers()
	local nearesttarget
	local maxDistance = 25 -- distance
	for i,player in pairs(players) do
		if player.Character then
			local target = player.Character
			local distance = (npc.HumanoidRootPart.Position - target:WaitForChild("HumanoidRootPart").Position).Magnitude
			if distance < maxDistance  then
				nearesttarget = target
				maxDistance = distance
				--print(target)
				--print("Found target, nearesttarget = target")
			end
			
			--if distance <= MaxAttackDistance and not AttackDebounce then
				--[[
				AttackDebounce = true
				if Swings == 0 then
				Attack1Anim:Play()
				Swings += 1
				else
					Attack2Anim:Play()
					Swings = 0
				end
				newHitbox:HitStart()
				local RandomSwingSound = SwingSounds[math.random(1, #SwingSounds)]
				RandomSwingSound:Play()
				task.wait(AttackCooldown)
				AttackDebounce = false--]]
			--end
			
		end
	end
	return nearesttarget
end

local function getPath(destination)
	local path = PFS:CreatePath()

	path:ComputeAsync(npc.HumanoidRootPart.Position, destination)

	return path
end
local function CheckRaycast()
	local target = findTarget()
	if target then
		local ray = Ray.new(npc.HumanoidRootPart.Position,(target.HumanoidRootPart.Position - npc.HumanoidRootPart.Position).unit * 100) -- create the ray
		local hit,pos = workspace:FindPartOnRay(ray,npc) -- find parts that the ray hit
		
		if hit then -- if the ray hit a part then
			
			if hit:IsDescendantOf(target) then -- if the part is part of the target's character then
				--foundtarget = 1
				return true -- return true
			end
		end
		--IsAttacking.Value = false
		--foundtarget = nil
		return false -- if no target was found, return false
	end
end


local function pathFindTo(destination)
	local path = getPath(destination)
	local target = findTarget()


	path.Blocked:Connect(function()
		path:Destroy()
	end)


if target and target.Humanoid.Health > 0 then
	for i,waypoint in pairs(path:GetWaypoints()) do

		if waypoint.Action == Enum.PathWaypointAction.Jump then
			human.Jump = true
		end
		IsAttacking.Value = true
		foundtarget = 1
		human.WalkSpeed = 18
		if CheckRaycast() == false then
			--print("Using Pathfinding, Should just be this printing")
		human:MoveTo(waypoint.Position)
		human.MoveToFinished:Wait()
		end

if CheckRaycast() == true then -- you're going to have to make your own checkraycast function
	repeat
		human:MoveTo(target.PrimaryPart.Position)
		task.wait()
		--print("Using Basic MoveTo(), Should just be this printing")
	until CheckRaycast() == false
	break
end
	end
end
end




while true do
	task.wait()
	--print('every frame bruh')
	local target = findTarget()
	task.spawn(function()
		if target then
			--print("Attacking"..target.Name)
			print('attackin')
			pathFindTo(target:WaitForChild("HumanoidRootPart").Position)
		else
			print('walking')
			walkRandomly()
		end
		end)
		CheckRaycast()
end
1 Like

Maybe this is your problem.
But you have two of the same part in the same script… That’s what functions are for.

Oh, and also remove the task.spawn. I think that’s your main problem. You should detect if the enemy changed and cancel the pathfinding.

clarify?

the task.spawn is there so that the if statement actually works in the while loop, but without the task.spawn the if statement doesnt work but the multiple waypoints thing is fixed

You need 2 threads in that case. One to determine the enemy and one to go to the enemy. You can also detect if the thread that does the pathfinding is running and you can choose to not run it again if it already is.

going to the enemy is irrelevant here. this is an example of the problem:

the NPC is walking to random waypoint around the map, however, instead of the NPC going to one waypoint, then onto the next, the NPC tries to go to all at once due to this function which is running in the while loop


function walkRandomly()
	--IsAttacking.Value = false
	local point = points[math.random(1,#points)]
	--local target = FindTarget()
	local path = game:GetService("PathfindingService"):CreatePath({
		AgentRadius = 2,
		AgentHeight = 5,
		AgentCanJump = true,
		Costs = {
			PathFindingModifier = math.huge
		}
	})
	path.Blocked:Connect(function()
		path:Destroy()
		print("DEBUG: PATH BLOCKED (WALKRANDOMLY)")
		walkRandomly()
	end)
	path:ComputeAsync(hrp.Position, point.Position)

	local waypoints = path:GetWaypoints()
	for _, waypoint in ipairs(waypoints) do
		if foundtarget == nil then
			--print("DEBUG: WALKING RANDOMLY TO WAYPOINT")
			--IsAttacking.Value = false
			human:MoveTo(waypoint.Position)
			IsAttacking.Value = false
			foundtarget = nil
			human.WalkSpeed = 8
			path.Blocked:Connect(function()
				path:Destroy()
				print("DEBUG: PATH BLOCKED (WALKRANDOMLY)")
				walkRandomly()
			end)
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				human:ChangeState(Enum.HumanoidStateType.Jumping)
			end
		end
		if IsAttacking.Value then path:Destroy() break end
		human.MoveToFinished:Wait()
		--FindTarget()
	end

end

Yeah, that’s the issue. You should add a debounce for this function to prevent it from running twice, which I think should work.

yeah but I want the path to keep being calculated over and over, because if i just added a debounce the path would only be calculated once and if wall or something moves infront of the path the NPC would just get stuck

Don’t go to all the waypoints in a sequence, only go to one, and then recalculate the path. This will solve your issue with the loop and task.spawn.

well yeah, but how would i do that

just add a break at the end of the for loop and remove the task.spawn.

function walkRandomly()
	--IsAttacking.Value = false
	local point = points[math.random(1,#points)]
	--local target = FindTarget()
	local path = game:GetService("PathfindingService"):CreatePath({
		AgentRadius = 2,
		AgentHeight = 5,
		AgentCanJump = true,
		Costs = {
			PathFindingModifier = math.huge
		}
	})
	path.Blocked:Connect(function()
		path:Destroy()
		print("DEBUG: PATH BLOCKED (WALKRANDOMLY)")
		walkRandomly()
	end)
	path:ComputeAsync(hrp.Position, point.Position)

	local waypoints = path:GetWaypoints()
	for _, waypoint in ipairs(waypoints) do
		if foundtarget == nil then
			--print("DEBUG: WALKING RANDOMLY TO WAYPOINT")
			--IsAttacking.Value = false
			human:MoveTo(waypoint.Position)
			IsAttacking.Value = false
			foundtarget = nil
			human.WalkSpeed = 8
			path.Blocked:Connect(function()
				path:Destroy()
				print("DEBUG: PATH BLOCKED (WALKRANDOMLY)")
				walkRandomly()
			end)
			if waypoint.Action == Enum.PathWaypointAction.Jump then
				human:ChangeState(Enum.HumanoidStateType.Jumping)
			end
		end
		if IsAttacking.Value then path:Destroy() break end
		human.MoveToFinished:Wait()
		--FindTarget()
		break
	end

end
--other stuff

while true do
	task.wait()
	--print('every frame bruh')
	local target = findTarget()
	--task.spawn(function()
		if target then
			--print("Attacking"..target.Name)
			print('attackin')
			pathFindTo(target:WaitForChild("HumanoidRootPart").Position)
		else
			print('walking')
			walkRandomly()
		end
		--end)
		CheckRaycast()
end

didn’t work; npc just stood still and nothing happened

just tried it myself and it didn’t work, could you put it in the script?

fixed this by using debounce, not the greatest fix but it worked