I made a script where the NPC follows the player using pathfinding.
local character = script.Parent
local humanoid = character.Humanoid
local chasing = false
local PathfindingService = game:GetService("PathfindingService")
local ignoreList = {character}
for i, v in pairs(workspace:GetDescendants()) do
-- Adds other NPCs and parts to be ignored
if v:IsA("Model") and v ~= character and v:FindFirstChildOfClass("Humanoid") then
table.insert(ignoreList, v)
print("Added "..v.Name.." to ignore list")
elseif v:IsA("Part") and v.Transparency >= 0.3 or v:FindFirstChild("SeeThrough") then
table.insert(ignoreList, v)
print("Added "..v.Name.." to ignore list")
end
-- Removes from ignore list when changed/deleted
v.Changed:Connect(function()
if v:IsA("Model") and v ~= character and v:FindFirstChildOfClass("Humanoid") then
table.remove(ignoreList, tonumber(v))
print("Removed "..v.Name.." to ignore list")
elseif v:IsA("Part") and v.Transparency < 0.3 then
table.remove(ignoreList, tonumber(v))
print("Removed "..v.Name.." to ignore list")
end
end)
v.Destroying:Connect(function()
if v:IsA("Model") and v ~= character and v:FindFirstChildOfClass("Humanoid") then
table.remove(ignoreList, tonumber(v))
print("Removed "..v.Name.." to ignore list")
elseif v:IsA("Part") and v.Transparency < 0.3 then
table.remove(ignoreList, tonumber(v))
print("Removed "..v.Name.." to ignore list")
end
end)
end
-- Main
local function canSeeTarget(target)
local origin = character.HumanoidRootPart.Position
local direction = (target.HumanoidRootPart.Position - character.HumanoidRootPart.Position).Unit * 500
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
raycastParams.FilterDescendantsInstances = {ignoreList}
local ray = workspace:Raycast(origin,direction,raycastParams)
if ray then
if ray.Instance:IsDescendantOf(target) then
return true
end
else
return false
end
end
local function findTarget()
local maxDistance = 100000
local nearestTarget = nil
for i, v in pairs(game.Players:GetPlayers()) do
if v.Character then
local target = v.Character
local distance = (character.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and canSeeTarget(target) and target.Humanoid.Health > 0 then
nearestTarget = target
maxDistance = distance
chasing = true
else
chasing = false
end
end
end
return nearestTarget
end
local function getPath(destination)
local path = PathfindingService:CreatePath(
{
["AgentHeight"] = 5,
["AgentRadius"] = 3,
["AgentCanJump"] = true
})
path:ComputeAsync(character.HumanoidRootPart.Position, destination.Position)
return path
end
local function waypointPath(pos: Vector3) -- Creates the path thingy
local part = Instance.new("Part")
part.Name = "Waypoint"
part.Size = Vector3.new(1,1,1)
part.Color = Color3.fromRGB(255, 0, 0)
part.CanCollide = false
part.CanQuery = false
part.CanTouch = false
part.Anchored = true
part.Position = pos
part.Parent = workspace
game.Debris:AddItem(part, 2)
return part
end
local function walkTo(destination,target)
local path = getPath(destination)
local waypoints = path:GetWaypoints()
if path.Status == Enum.PathStatus.Success then
for index, waypoint in pairs(waypoints) do
--waypointPath(waypoint.Position)
humanoid:MoveTo(waypoint.Position)
end
end
end
while true do
task.wait()
local target = findTarget()
if target then
walkTo(target.HumanoidRootPart,target)
end
end
How it should work
The NPC follows the player when the player is in its sight. If the wall’s transparency is at least 0.3 or contains a boolvalue named “SeeThrough”, it ignores it and walks to the player.
If there are many NPCs with the same follow script, they should not follow the player in groups.
Problems
If the wall’s transparency is 0.3 and higher or if it has the “SeeThrough” boolvalue, it walks to the player, but it just collides with the wall instead of moving to the sides in order to get to the player. If the wall is deleted and when I go past through it, the NPC follows me, but when I go behind the wall which was deleted, the NPC stopped following me when it reached the position of the deleted. When changing or deleting these, it doesn’t remove them from the ignore list.
When there many NPCs following the player, they’re following me in groups or line up, colliding with each other instead of spreading.
I’ve searched topics related to this, but none of these helps.
make a table for the parts(lines) and place tiny parts sizes to 1,1,1 and put them in the center of the corners and make the rigs travel to the parts like
for i=1, part in ipairs(PartsFolder) do
character:MoveTo(part.Position)
character.MoveToFinished:Wait()
end
I got confused and don’t know what to do with this but I added MoveToFinished after :MoveTo(). Now they only follow the last position I was standing on in a straight line.
Could you do a change to while-loop Into this code ?
Also you might consider doing for-loop in native instead of pairs or ipairs since you used it with not using it for some feature (they waste some perfomance, see it’s bytecode)
-- this is possible, locking into 60 fps rate
while task.wait() do
-- yours code here
end
-- this is also possible
for i,v in tablehere do
end
local character = script.Parent
local humanoid = character.Humanoid
local chasing = false
local PathfindingService = game:GetService("PathfindingService")
local ignoreList = {character}
for i, v in pairs(workspace:GetDescendants()) do
-- Adds other NPCs and parts to be ignored
if v:IsA("Model") and v ~= character and v:FindFirstChildOfClass("Humanoid") then
table.insert(ignoreList, v)
print("Added "..v.Name.." to ignore list")
elseif v:IsA("Part") and v.Transparency >= 0.3 or v:FindFirstChild("SeeThrough") then
table.insert(ignoreList, v)
print("Added "..v.Name.." to ignore list")
end
-- Removes from ignore list when changed/deleted
v.Changed:Connect(function()
if v:IsA("Model") and v ~= character and v:FindFirstChildOfClass("Humanoid") then
table.remove(ignoreList, tonumber(v))
print("Removed "..v.Name.." to ignore list")
elseif v:IsA("Part") and v.Transparency < 0.3 then
table.remove(ignoreList, tonumber(v))
print("Removed "..v.Name.." to ignore list")
end
end)
v.Destroying:Connect(function()
if v:IsA("Model") and v ~= character and v:FindFirstChildOfClass("Humanoid") then
table.remove(ignoreList, tonumber(v))
print("Removed "..v.Name.." to ignore list")
elseif v:IsA("Part") and v.Transparency < 0.3 then
table.remove(ignoreList, tonumber(v))
print("Removed "..v.Name.." to ignore list")
end
end)
end
-- Main
local function canSeeTarget(target)
local origin = character.HumanoidRootPart.Position
local direction = (target.HumanoidRootPart.Position - character.HumanoidRootPart.Position).Unit * 500
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Exclude
raycastParams.FilterDescendantsInstances = {ignoreList}
local ray = workspace:Raycast(origin,direction,raycastParams)
if ray then
if ray.Instance:IsDescendantOf(target) then
return true
end
else
return false
end
end
local function findTarget()
local maxDistance = 100000
local nearestTarget = nil
for i, v in game.Players:GetPlayers() do
if v.Character then
local target = v.Character
local distance = (character.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and canSeeTarget(target) and target.Humanoid.Health > 0 then
nearestTarget = target
maxDistance = distance
chasing = true
else
chasing = false
end
end
end
return nearestTarget
end
local function getPath(destination)
local path = PathfindingService:CreatePath(
{
["AgentHeight"] = 5,
["AgentRadius"] = 3,
["AgentCanJump"] = true
})
path:ComputeAsync(character.HumanoidRootPart.Position, destination.Position)
return path
end
local function waypointPath(pos: Vector3) -- Creates the path thingy
local part = Instance.new("Part")
part.Name = "Waypoint"
part.Size = Vector3.new(1,1,1)
part.Color = Color3.fromRGB(255, 0, 0)
part.CanCollide = false
part.CanQuery = false
part.CanTouch = false
part.Anchored = true
part.Position = pos
part.Parent = workspace
game.Debris:AddItem(part, 5)
return part
end
local function walkTo(destination,target)
local path = getPath(destination)
local waypoints = path:GetWaypoints()
if path.Status == Enum.PathStatus.Success then
for index, waypoint in waypoints do
waypointPath(waypoint.Position)
humanoid:MoveTo(waypoint.Position)
humanoid.MoveToFinished:Wait()
end
end
end
while task.wait() do
local target = findTarget()
if target then
walkTo(target.HumanoidRootPart,target)
end
end
But how do I make it so it doesn’t walk to the last time I was standing on? And also how do I make multiple NPCs follow the player spread when they get too close to each other instead of bumping?
You will want to get all nearby NPCs similar to how you did it for the nearest target. Compare all other NPC’s position. Count how much NPCs are too close to the current NPC, if there is too much, then stop the current path, and in the next getPath call, calculate a random vector combination of X and Z like + Vector3.new(math.random(-5, 5), 0, math.random(-5, 5)) so that the point to travel to can be a random point in a plane with the origin at the target’s root. Then call path:ComputeAsync to that new point instead of directly at the target’s root.