Help with Pathfinding

I want to make the Cop NPC pathfind to a crimminal if the boolvalue inside the crimminal is true. The problem is that it doesn’t work.

Code:

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

local character = script.Parent
local humanoid = character:WaitForChild("Humanoid")
local WalkSpeed = humanoid.WalkSpeed

local DestinationsFolder = workspace:WaitForChild("Destinations")
character.PrimaryPart:SetNetworkOwner(nil)

local nextActivate = os.clock()
local debounceTime = 0.3
local combo = 1

local animationTable = {
	script:WaitForChild("Animation"),
	script:WaitForChild("Animation2"),
}

local waypoints
local pathFound = false
local isChasing = false

local function randomWaypoint()
	local waypoint = DestinationsFolder:GetChildren()
	local random = waypoint[math.random(1, #waypoint)]
	return random
end

local function findTarget()
	local nearesttarget
	local maxDistance = 500

	for i,v in ipairs(workspace:WaitForChild("Npcs"):GetChildren()) do
		if v:IsA("Model") and v:FindFirstChildWhichIsA("Humanoid") then
			local human = v:FindFirstChildWhichIsA("Humanoid")

			if v:FindFirstChild("Wanted") and v:FindFirstChild("Wanted").Value == true then
				local distance = (character.PrimaryPart.Position - v.PrimaryPart.Position).Magnitude

				if distance <= maxDistance then
					nearesttarget = v
					maxDistance = distance
				end
			end
		end
	end
	return nearesttarget
end

local function WalkTo(destination)
	local pathParams = {
		AgentHeight = character:GetExtentsSize().Y,
		AgentRadius = character:GetExtentsSize().X,
		AgentCanJump = false,
		Costs = {
			Danger = math.huge,
		}
	}

	local path = PathfindingService:CreatePath(pathParams)
	local Blocked = false

	local success, errorMessage = pcall(function()
		path:ComputeAsync(character.PrimaryPart.Position, destination.Position)
	end)

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

		path.Blocked:Connect(function(blockedWaypointIndex)
			Blocked = true
			path:ComputeAsync(character.PrimaryPart.Position, destination.Position)
		end)

		for i,v in pairs(waypoints) do
			repeat
				humanoid:MoveTo(v.Position)
			until humanoid.MoveToFinished:Wait() or Blocked
			
			if Blocked then
				repeat task.wait(1)
					WalkTo(destination)
				until success and path.Status == Enum.PathStatus.Success
			end
		end
		
		pathFound = false
	end
end

humanoid:GetPropertyChangedSignal("Health"):Connect(function()
	coroutine.wrap(function()
		humanoid.WalkSpeed = 16
		task.wait(10)
		humanoid.WalkSpeed = WalkSpeed
	end)()
end)


RunService.Heartbeat:Connect(function()
	if findTarget() ~= nil and not pathFound then
		isChasing = true
		humanoid.WalkSpeed = 16
		WalkTo(findTarget().PrimaryPart)
		pathFound = true

	elseif findTarget() == nil then
		if isChasing and not pathFound then
			isChasing = false
			humanoid.WalkSpeed = WalkSpeed
			WalkTo(randomWaypoint())
			pathFound = true
		end
	end
end)



Link to edit the game

A Couple of things,

You should Create the path Outside of functions, instead what you are doing is creating a new Path with Agent Params, This is useless to do, ComputeAsync is the Item you are looking for if you want the NPC to follow a Specific path:

local Path: Path =  PathfindingService:CreatePath(pathParams)

function Follow(destination: Vector3?)
    local success, result = pcall(function()
        Path:ComputeAsync(character.PrimaryPart.Position, desintation)
    end) 

This will still work, and I’m sure it wont cause issues.


Another thing I see is that you are using loops, this wont make the Pathfinding Better but only Disrupt it from doing what it has to do. So it would be best to remove them.


Another thing I noticed is that you are making the for loop more complicated than it needs to be, If you are string NPC’s within the NPC Folder, you don’t have to worry if they don’t have a Humanoid or not as they will always have it.

Plus, You are using this if statement incorrectly:
if v:FindFirstChild("Wanted") and v:FindFirstChild("Wanted").Value == true then
This can easily be simplified to:
if v:FindFirstChild("Wanted").Value then
What this does does is check if the Instance is not nil and true.

You should Also use use Attributes for this occasion.

This should be the Fixed Version:

NPCs = workspace:WaitForChild("Npcs")
function GetTarget()
    local Nearest
    local MaxDist = 500
    local Dist
    for _,p in NPCs:GetChildren() do
        if v:IsA("Model") then -- If Item is a Model
            local Hum = v:FindFirstChild("Humanoid") -- Gets Humanoid
            
            if v:GetAttribute("Wanted") then
            Dist = (character.PrimaryPart.Position - v.PrimaryPart.Position).Magnitude -- Distance
                if Dist <= MaxDist then -- Distance Check
                    Nearest = v -- New Target
                    MaxDist = Dist -- New Limit to Iterate through
                end
            end
        end
    end
    return Nearest -- returns Target
end

The problem I have is this part:

RunService.Heartbeat:Connect(function()
	if findTarget() ~= nil and not pathFound then
		print("not nil")
		isChasing = true
		humanoid.WalkSpeed = 16
		WalkTo(findTarget().PrimaryPart)
		pathFound = true

	elseif findTarget() == nil then
		if isChasing and not pathFound then
			print("1")
			isChasing = false
			humanoid.WalkSpeed = WalkSpeed
			WalkTo(randomWaypoint())
			pathFound = true
		end
	end
end)
local function check()
	for i,v in ipairs(workspace:WaitForChild("Npcs"):GetChildren()) do
		if v:IsA("Model") and v:FindFirstChildWhichIsA("Humanoid") then
			local human = v:FindFirstChildWhichIsA("Humanoid")
			
			if v:FindFirstChild("Wanted") and v:FindFirstChild("Wanted").Value == false then
				isChasing = false
				humanoid.WalkSpeed = WalkSpeed
				WalkTo(randomWaypoint())
			end
		end
	end
end

RunService.Heartbeat:Connect(function()
	if findTarget() ~= nil and not pathFound then
		print("not nil")
		isChasing = true
		humanoid.WalkSpeed = 16
		WalkTo(findTarget().PrimaryPart)
		pathFound = true

	elseif findTarget() == nil then
		print("nil")
		if isChasing and not pathFound then
			isChasing = false
			humanoid.WalkSpeed = WalkSpeed
			WalkTo(randomWaypoint())
			pathFound = true
		end
	end
	
	check()
end)

Can be Simplified:

local Target = GetTarget()

if Target then
   isChasing = true
   pathFound = true
   WalkTo(Target.PrimaryPart.Position)
else
    if isChasing and not pathFound then
        isChasing = false
        pathFound = false
        return
    end
end

The problem:

I don’t really like to simplify.

1 Like

You’re making your code more complicated than it needs to be, so yes, Its best to simplify if it will work the exact same.

I’m too lazy to do it but all I need to achieve is fixing the Cop NPC.

That’s Probably why nobody is helping you.

RunService.Heartbeat:Connect(function()
	if findTarget() and findTarget() ~= nil then
		humanoid.WalkSpeed = 20
		WalkTo(findTarget().PrimaryPart)
		
	elseif findTarget() == nil and not pathFound then
		pathFound = true
		humanoid.WalkSpeed = WalkSpeed
		WalkTo(randomWaypoint())
	end
end)

Updated Code.

This is the only part I need help with.

I have solved it! I spent hours on it and I have figured it out!

1 Like

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