Help with Pathfinding

So I need help with my police npc that chases an npc if the npc is wanted. I use a boolvalue inside the npc. So everything works, but when the npc is not wanted anymore, the police does not know where to go. It just goes crazy.

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") -- Red Parts in the video
character.PrimaryPart:SetNetworkOwner(nil)

local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection

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
			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
				
				if distance <= 8 then
					
				end
			end
		end
	end
	return nearesttarget
end

local function WalkTo(destination)
	local pathParams = {
		AgentHeight = character:GetExtentsSize().Y,
		AgentRadius = character:GetExtentsSize().Z,
		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)
		
		if not reachedConnection then
			reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
				if reached and nextWaypointIndex < #waypoints then
					nextWaypointIndex += 1
					repeat
						humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
					until humanoid.MoveToFinished:Wait() or Blocked
				else
					reachedConnection:Disconnect()
				end
			end)
		end
		
		nextWaypointIndex = 2
		humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
	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 then
		humanoid.WalkSpeed = 16
		WalkTo(findTarget().PrimaryPart)
	else
		humanoid.WalkSpeed = WalkSpeed
		WalkTo(randomWaypoint())
	end
end)


In this video: the police chased the npc with the red highlight. After I turned the bool into false, the police does not know where to go. (I disabled the bool at 9 seconds)

2 Likes

I know the problem but I’m not smart to solve it

RunService.Heartbeat:Connect(function()
	if findTarget() ~= nil then
		humanoid.WalkSpeed = 16
		WalkTo(findTarget().PrimaryPart)
	else
		humanoid.WalkSpeed = WalkSpeed
		WalkTo(randomWaypoint()) <-------
	end
end)
1 Like

You can add a flag to check if the police is currently chasing a target, and reset the flag and destination when the target is no longer wanted. You can add the following code to do this:

local isChasing = false
local target = nil

local function findTarget()
  target = nil
  local nearesttarget
  local maxDistance = 500

  for i,v in ipairs(workspace:WaitForChild("Npcs"):GetChildren()) do
    if v:IsA("Model") and v:FindFirstChildWhichIsA("Humanoid") then
      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

        if distance <= 8 then
        end
      end
    end
  end
  target = nearesttarget
  return nearesttarget
end

RunService.Heartbeat:Connect(function()
  if findTarget() ~= nil then
    isChasing = true
    humanoid.WalkSpeed = 16
    WalkTo(findTarget().PrimaryPart)
  else
    if isChasing then
      isChasing = false
      humanoid.WalkSpeed = WalkSpeed
      WalkTo(randomWaypoint())
    end
  end
end)

game.Workspace.Npcs.ChildAdded:Connect(function(child)
  if child == target and child:FindFirstChild("Wanted") and child:FindFirstChild("Wanted").Value == false then
    isChasing = false
    humanoid.WalkSpeed = WalkSpeed
    WalkTo(randomWaypoint())
  end
end)

1 Like

Also, how can I make the npc go to a random destination after reaching it’s destination?

reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
				if reached and nextWaypointIndex < #waypoints then
					nextWaypointIndex += 1
					repeat
						humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
					until humanoid.MoveToFinished:Wait() or Blocked
				else
					print("reached")
					reachedConnection:Disconnect()
				end
			end)
1 Like

You can make the NPC go to a random destination by generating a random number within the range of the number of waypoints available, and then using that number as the index for the next waypoint to move to. Here’s an example:

reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
	if reached and nextWaypointIndex < #waypoints then
		local nextIndex = math.random(1, #waypoints)
		nextWaypointIndex = nextIndex
		humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
	else
		print("reached")
		reachedConnection:Disconnect()
	end
end)

1 Like

I was talking about this part:

if reached and nextWaypointIndex < #waypoints then
					nextWaypointIndex += 1
					repeat
						humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
					until humanoid.MoveToFinished:Wait() or Blocked
				else
					print("reached") <---------- make it go to a random destination
					reachedConnection:Disconnect()
				end
1 Like

You can add the following code after print("reached") to make the NPC go to a random destination:

nextWaypointIndex = math.random(#waypoints)
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)

This will set nextWaypointIndex to a random index in the waypoints table, and then move the NPC to that position.

1 Like

That would make the NPC ignore the PathParams.

1 Like

Yes, that is correct. If you do not specify the PathParams, the NPC will move towards its destination in a straight line and ignore any obstacles in its path. To have the NPC navigate around obstacles and find the optimal path, you will need to provide PathParams.

1 Like
reachedConnection:Disconnect()
					nextWaypointIndex = math.random(#waypoints)
					path:ComputeAsync(character.PrimaryPart.Position, waypoints[nextWaypointIndex].Position)
					humanoid:MoveTo(waypoints[nextWaypointIndex].Position)

I tried this

1 Like

This code will disconnect the current reachedConnection event and then set the nextWaypointIndex to a random value from 1 to the length of the waypoints table. Then, it computes a new path from the character’s current position to the randomly selected waypoint position. Finally, it makes the humanoid move to that random waypoint. This should make the NPC go to a random destination after reaching its current destination.

1 Like

How can I add the PathParams? The code only tells the npc to go to the destination.

1 Like

You can add PathParams to the MoveTo function by passing it as a second argument. For example:

local pathParams = PathParams.new()
humanoid:MoveTo(waypoints[nextWaypointIndex].Position, pathParams)

You can then set the desired values for the PathParams object, such as MaxSpeed , Jump or Rounding to control the way the NPC moves.

For example:

pathParams.MaxSpeed = 10
pathParams.Jump = false
pathParams.Rounding = 10
1 Like

This got an error.

humanoid:MoveTo(waypoints[nextWaypointIndex].Position, pathParams)

Unable to cast value to Object

1 Like

Is this how PathParmas is supposed to be done?

local pathParams = {
		AgentHeight = character:GetExtentsSize().Y,
		AgentRadius = character:GetExtentsSize().Z,
		AgentCanJump = false,
		Costs = {
			Danger = math.huge,
		}
	}
2 Likes

This error is likely because MoveTo method only accepts one argument, the destination, and doesn’t have an option to pass additional parameters. To use PathParams while moving the NPC to the destination, you can create a new instance of PathParams and pass it to the ComputeAsync method before calling the MoveTo method. Here’s an example:

local pathParams = PathfindingService:CreatePathParams()
pathParams.AllowSWIM = false
pathParams.Avoidance = 0.5
pathParams.Heuristics = 0.5
pathParams.Jumps = false
pathParams.MaxAcceleration = 0.5

nextWaypointIndex = math.random(#waypoints)
path:ComputeAsync(character.PrimaryPart.Position, waypoints[nextWaypointIndex].Position, pathParams)
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
1 Like

Well it only takes 1 step after the npc reaches it’s destination.

1 Like

yea, that also can work!

another example:

local character = game.Workspace.Character
local humanoid = character.Humanoid
local pathParams = {
	AgentHeight = character:GetExtentsSize().Y,
	AgentRadius = character:GetExtentsSize().Z,
	AgentCanJump = false,
	Costs = {
		Danger = math.huge,
	}
}

-- Create an array of waypoints
local waypoints = {
	game.Workspace.Waypoint1,
	game.Workspace.Waypoint2,
	game.Workspace.Waypoint3
}

-- Choose a random starting waypoint
local nextWaypointIndex = math.random(#waypoints)

-- Connect to the MoveToFinished event
local reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
	if reached and nextWaypointIndex < #waypoints then
		nextWaypointIndex += 1
		humanoid:MoveTo(waypoints[nextWaypointIndex].Position, pathParams)
	else
		print("Reached destination")
		reachedConnection:Disconnect()
	end
end)

-- Start moving to the first waypoint
humanoid:MoveTo(waypoints[nextWaypointIndex].Position, pathParams)
1 Like

The NPC stops moving after reaching it’s destination. (Cop NPC)

2 Likes

This issue could be caused by several things, such as a missing connection to the MoveToFinished event or a failure to recalculate the path. Here’s an updated version of the code that addresses these possible issues:

local function MoveToNextWaypoint()
    local pathParams = PathfindingService:CreatePathParams()
    pathParams.AllowSWIM = false
    pathParams.Avoidance = 0.5
    pathParams.Heuristics = 0.5
    pathParams.Jumps = false
    pathParams.MaxAcceleration = 0.5

    nextWaypointIndex = nextWaypointIndex + 1
    if nextWaypointIndex > #waypoints then
        -- all waypoints have been reached
        return
    end

    local destination = waypoints[nextWaypointIndex].Position
    local connection
    connection = humanoid.MoveToFinished:Connect(function()
        -- NPC has reached the destination, move to the next waypoint
        connection:Disconnect()
        MoveToNextWaypoint()
    end)
    path:ComputeAsync(character.PrimaryPart.Position, destination, pathParams)
    humanoid:MoveTo(destination)
end

-- start moving to the first waypoint
nextWaypointIndex = 1
MoveToNextWaypoint()

In this updated version, a new local variable connection is created to keep track of the connection to the MoveToFinished event. The connection is disconnected after the NPC has reached its destination, which should ensure that it continues moving to the next waypoint. Additionally, the ComputeAsync method is called before the MoveTo method to ensure that a valid path is always available for the NPC to follow.

1 Like