# NPC "Squad" Pathfinding not working and can't find out why?

The primary goal of this script is to control a “squad” of NPCs using pathfinding to move towards a target (player) and attack them if within range.

(This script is in its early stages so I’m really just trying to get the NPC’s to FOLLOW the nearest player at the moment)
(Many functions that I plan to implement later)

The issue is that the squad of NPC’s are supposed to follow their “Commander”
Then seek and follow (attack) the nearest player however they are just idling where they spawn.
And the worst thing is that the output screen says nothing and I have checked if it run’s until the end using “print” and it does.

I have looked online, watched tutorials and even asked ChatGPT to have a look at it.

I don’t really post on the Dev Forums too often so I apologise if something is unclear.
And thanks for any help provided

local PathfindingService = game:GetService("PathfindingService")
local squad = {} -- Holds the members of the special response team

-- Helper Functions
local function calculateDangerLevel(player)
-- Implement code to calculate the player's danger level based on their equipped weapons and other factors
-- Assign a numerical value to each weapon and calculate the total danger level accordingly
return 0
end

local function findNearestPlayer(position)
-- Implement code to find the nearest player to a given position  within a certain radius
local players = game:GetService("Players"):GetPlayers()
local nearestPlayer, minDistance = nil, math.huge
for _, player in ipairs(players) do
if player.Character and player.Character:FindFirstChild("HumanoidRootPart") then
local distance = (player.Character.HumanoidRootPart.Position - position).Magnitude
if distance < SEARCH_RADIUS and distance < minDistance then
minDistance = distance
nearestPlayer = player.Character.HumanoidRootPart.Position
end
end
end
return nil
end

-- Implement code to add the member to the squad and set their initial behavior
table.insert(squad, {member = member, role = role})

-- Set the member's role-specific behavior
if role == "Commander" then
-- Set the commander's behavior here (e.g., guide other squad members, attack players based on threat level)
-- You can assign the shotgun and light combat armor to the model instance of the commander
elseif role == "Spotter" then
-- Set the spotter's behavior here (e.g., spot players from long distances, alert others, target through walls)
-- You can assign the Battle Rifle (AR15) and special targeting goggles to the model instance of the spotter
elseif role == "Sniper" then
-- Set the sniper's behavior here (e.g., shoot players from long distances, fall back if targeted player gets too close)
-- You can assign the sniper rifle to the model instance of the sniper
elseif role == "Medic" then
-- Set the medic's behavior here (e.g., passively heal wounded squad members)
-- You can assign the pistol and medkit to the model instance of the medic
elseif role == "Gunner" then
-- Set the gunner's behavior here (e.g., rely on suppressing fire, higher armor rating)
-- You can assign the Light Machine Gun and Heavy combat armor to the model instance of the gunner
end
end

local Commander = game.Workspace.Commander
local Spotter = game.Workspace.Spotter
local Sniper = game.Workspace.Sniper
local Medic = game.Workspace.Medic
local Gunner = game.Workspace.Gunner

-- Function to set the squad's target
-- Implement code to set the target for the squad
end

-- Main AI Function
local function SpecialResponseTeamAI()
while true do
wait(1) -- Adjust the delay as needed to control the AI behavior frequency

-- Check if the squad has a target
-- If there's no target, find the nearest player to attack
if nearestPlayer then
local dangerLevel = calculateDangerLevel(nearestPlayer)
if dangerLevel > 0 then
end
end
else
-- If there's a target, move towards them and attack if within range
for _, memberData in ipairs(squad) do
local member = memberData.member
local role = memberData.role

if member:IsA("Model") and member:FindFirstChild("HumanoidRootPart") and member.Humanoid.Health > 0 then
local pathPoints = {
}
local pathParams = PathfindingService:CreatePath({
AgentHeight = 5, -- Adjust the height as needed
AgentCanJump = true,
AgentJumpHeight = 10, -- Adjust the jump height as needed
AgentMaxSlope = 45, -- Adjust the max slope angle as needed
})
pathParams:ComputeAsync(unpack(pathPoints))
local path = pathParams.Status == Enum.PathStatus.Success and pathParams or nil

if path then
while true do
member.Humanoid:MoveTo(path:GetPointAtIndex(2)) -- Start moving towards the next point in the path
if (member.HumanoidRootPart.Position - squad[1].member.HumanoidRootPart.Position).magnitude <= 3 then
-- Make other squad members closely follow the Commander (within a distance of 3 studs)
end
-- Implement code for attacking the target player based on the member's role
--
if role == "Commander" then
-- Commander's attack logic
elseif role == "Spotter" then
-- Spotter's attack logic
elseif role == "Sniper" then
-- Sniper's attack logic
elseif role == "Medic" then
-- Medic's attack logic
elseif role == "Gunner" then
-- Gunner's attack logic
end
end
-- Check if the squad no longer has a target or the squad member is defeated
if not squad.target or member.Humanoid.Health <= 0 then
break
end

wait(0.1) -- Adjust the delay as needed for smooth movement
end
end
end
end
end
end
end

return SpecialResponseTeamAI

1 Like

• The calculateDangerLevel function always returns 0, and later down, your main AI is checking if it’s bigger than 0. That means that there isn’t a situation where the squad.Target isn’t nil, meaning that the pathfinding part will simply never happen.

1 Like
1. I believe the roles for each squad member are assigned accordingly from lines 68 - 77 but if that is the problem I assume the pathfinding would still work regardless

2. I cooked up this code below to set the default DangerLevel to 1 (Which it should of been thank you for pointing that out) and also made it so if a player has a tool on them, their threat level should increase though nothing changed?

-- Helper Functions
local function calculateDangerLevel(player)
-- Implement code to calculate the player's danger level based on their equipped weapons and other factors
-- Assign a numerical value to each weapon and calculate the total danger level accordingly
local dangerLevel = 1 -- Default danger level

local character = player.Character
if character then
local humanoid = character:FindFirstChildOfClass("Humanoid")
if humanoid then
local equippedWeapon = humanoid:FindFirstChildOfClass("Tool")
if equippedWeapon then
dangerLevel = dangerLevel + 1 -- Assign a higher danger level if the player is carrying a weapon
end
end
end

return dangerLevel
end

1 Like

I must also Clarifiy This specific script is a ModuleScript which is being required by a server-side script.

1 Like

I have to ask, does the Server Script actually call the commands when necessary? The main AI function seems to be a local function, which shouldn’t be accessible when calling functions. Maybe change it to simply “function”, and test it out to see what happens?

1 Like

I made the change though nothing interesting happened, neither did anything appear in the output menu. But I did make a discovery myself, adding print statements throughout different sections of the main AI function the only ones activated is a print statement just before the function and just after.

Do you mean the calculateDangerLevel function?

I’m sorry, but it’s really late at night here so I can barely function

No the SpecialResponseTeamAI function

And its alright take your time if you need to we can always continue this another day if needed