You can write your topic however you want, but you need to answer these questions:
- What do you want to achieve? Keep it simple and clear!
i am working on an ai that patrols and chases players with line of sight, however even without a player, the ai stutters the longer its running
-
What solutions have you tried so far? Did you look for solutions on the Developer Hub?
and no, dont ask me to use networkowner as i did try setting network and networkownershipauto and looping it for all parts in the ai, it still stutters
After that, you should include more details if you have any. Try to make your topic as descriptive as possible, so that it’s easier for people to help you!
this is the ai code that is responsible for checking for line of sight and chasing players
local teddy = script.Parent
local humanoid = teddy.Humanoid
local ChaseTorso = nil
teddy.HumanoidRootPart:SetNetworkOwner(nil)
local PathParams = {
["Agentheight"] = 4,
["AgentRadius"] = 5,
["AgentCanJump"] = false
}
local path = game:GetService("PathfindingService"):CreatePath(PathParams)
spawn(function()
while wait() do
for i, v in ipairs(script.Parent:GetDescendants()) do
if v:IsA("BasePart") then
v.CollisionGroup = "Begulas"
v:SetNetworkOwner(nil)
v:SetNetworkOwnershipAuto(nil)
end
end
end
end)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local viewRange = 220 -- How far the NPC can see in studs
local fieldOfView = 80 -- The NPC's field of view in degrees
local TargetCharacter = nil
local TargetCharacterPosition = nil
local function canSeeTarget(target)
local origin = teddy.HumanoidRootPart.Position
local direction = (target.HumanoidRootPart.Position - teddy.HumanoidRootPart.Position).unit * 60
local ray = Ray.new(origin, direction)
local hit, pos = workspace:FindPartOnRay(ray, teddy)
if hit then
if hit:IsDescendantOf(target) then
return true
end
else
return false
end
end
local function findTarget()
local players = game.Players:GetPlayers()
local maxDistance = 125
local nearestTarget
for index, player in pairs(players) do
if player.Character then
local target = player.Character
local distance = (teddy.HumanoidRootPart.Position - target.HumanoidRootPart.Position).Magnitude
if distance < maxDistance and canSeeTarget(target) then
nearestTarget = target
maxDistance = distance
end
end
end
return nearestTarget
end
local function getPath(destination)
local PathfindingService = game:GetService("PathfindingService")
local path = PathfindingService:CreatePath(PathParams)
path:ComputeAsync(teddy.HumanoidRootPart.Position, destination)
return path
end
local function attack(target)
local distance = (teddy.HumanoidRootPart.Position - ChaseTorso.Position).Magnitude
local path = getPath(ChaseTorso)
if distance > 8 then
if path.Status == Enum.PathStatus.Success then
for index, waypoint in pairs(path:GetWaypoints()) do
humanoid.WalkSpeed = 32
humanoid:MoveTo(waypoint.Position)
end
end
else
humanoid:MoveTo(ChaseTorso.Position - (teddy.HumanoidRootPart.CFrame.LookVector * 10))humanoid:MoveTo(ChaseTorso.Position)
humanoid.WalkSpeed = 26
end
end
local function walkTo(destination)
-- Compute the path
local timeOut = teddy.Humanoid.MoveToFinished:Wait(1)
if not timeOut then
print("attempting to unstuck")
blockedConnection:Disconnect()
reachedConnection:Disconnect()
waypoints = nil
nextWaypointIndex = nil
walkTo(destination)
end
local success, errorMessage = pcall(function()
path:ComputeAsync(teddy.HumanoidRootPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Get the path waypoints
waypoints = path:GetWaypoints()
-- Detect if path becomes blocked
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Check if the obstacle is further down the path
if blockedWaypointIndex >= nextWaypointIndex then
-- Stop detecting path blockage until path is re-computed
blockedConnection:Disconnect()
-- Call function to re-compute new path
walkTo(destination)
end
end)
-- Detect when movement to next waypoint is complete
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Increase waypoint index and move to next waypoint
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Initially move to second waypoint (first waypoint is path start; skip it)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
function CheckForVisibility(Character)
local headPosition = teddy.Head.Position
local objectPosition = Character.Head.Position
local headCFrame = teddy.Head.CFrame
local npcToObject = (objectPosition - headPosition).Unit
local npcLookVector = headCFrame.LookVector
local dotProduct = npcToObject:Dot(npcLookVector)
local angle = math.deg(math.acos(dotProduct))
local distance = (headPosition - objectPosition).Magnitude
if angle > fieldOfView then
return false
end
if distance > viewRange then
return false
end
if not canSeeTarget(Character) then
return false
end
if Character.Hiding.Value then
return false
end
return true
end
spawn(function()
while wait() do
wait(math.random(3,7))
script.Parent.Head:FindFirstChild("Ambient"..math.random(1,4)):Play()
end
end)
while wait() do
if TargetCharacter == nil then
script.Parent.AIMovementBehavior.Enabled = true
local VisiblePlayers = {}
local ClosestPlayer = nil
local Distance = 1e6
for i, v in ipairs(game.Players:GetPlayers()) do
if v and v.Character then
if CheckForVisibility(v.Character) then
table.insert(VisiblePlayers, v)
end
end
end
if #VisiblePlayers >= 1 then
TargetCharacter = VisiblePlayers[math.random(1,#VisiblePlayers)].Character
end
else
if CheckForVisibility(TargetCharacter) then
TargetCharacterPosition = TargetCharacter.PrimaryPart.Position
end
script.Parent.AIMovementBehavior.Enabled = false
walkTo(TargetCharacterPosition)
spawn(function()
if not CheckForVisibility(TargetCharacter) or not getPath(TargetCharacter.PrimaryPart.Position) then
repeat wait()
until CheckForVisibility(TargetCharacter) or (TargetCharacterPosition - teddy.PrimaryPart.Position).Magnitude <= 6 or not getPath(TargetCharacter.PrimaryPart.Position)
if not CheckForVisibility(TargetCharacter) or not getPath(TargetCharacter.PrimaryPart.Position) then
TargetCharacter = nil
end
end
end)
end
end
this one is responsible for wandering
local teddy = script.Parent
local humanoid = teddy.Humanoid
teddy.HumanoidRootPart:SetNetworkOwner(nil)
local PathParams = {
["Agentheight"] = 4,
["AgentRadius"] = 5,
["AgentCanJump"] = false
}
local path = game:GetService("PathfindingService"):CreatePath(PathParams)
local waypoints
local nextWaypointIndex
local reachedConnection
local blockedConnection
local function walkTo(destination)
-- Compute the path
local success, errorMessage = pcall(function()
path:ComputeAsync(teddy.HumanoidRootPart.Position, destination)
end)
if success and path.Status == Enum.PathStatus.Success then
-- Get the path waypoints
waypoints = path:GetWaypoints()
-- Detect if path becomes blocked
blockedConnection = path.Blocked:Connect(function(blockedWaypointIndex)
-- Check if the obstacle is further down the path
if blockedWaypointIndex >= nextWaypointIndex then
-- Stop detecting path blockage until path is re-computed
blockedConnection:Disconnect()
-- Call function to re-compute new path
walkTo(destination)
end
end)
-- Detect when movement to next waypoint is complete
if not reachedConnection then
reachedConnection = humanoid.MoveToFinished:Connect(function(reached)
if reached and nextWaypointIndex < #waypoints then
-- Increase waypoint index and move to next waypoint
nextWaypointIndex += 1
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
end)
end
-- Initially move to second waypoint (first waypoint is path start; skip it)
nextWaypointIndex = 2
humanoid:MoveTo(waypoints[nextWaypointIndex].Position)
else
warn("Path not computed!", errorMessage)
end
end
function patrol()
local waypoints = script.Parent.Parent.Waypoints:GetChildren()
local randomNum = math.random(1, #waypoints)
print("Pathfinding")
repeat task.wait(.05)
walkTo(waypoints[randomNum].Position)
until (teddy.HumanoidRootPart.Position - waypoints[randomNum].Position).Magnitude <= 6
print("Reached")
nextWaypointIndex = nil
waypoints = {}
reachedConnection:Disconnect()
blockedConnection:Disconnect()
end
while wait(0.25) do
patrol()
end