Hello. I have been having some problems with my AI for about a year now. I thought it’s finally time to get some DevForum help, but anyways.
I have a game where tons of NPCs spawn that use this build of AI. This AI is very laggy and pretty dumb.
Example:
Let’s say my AI targets an enemy with 10,000 HP. The AI will refuse to look for any other targets until that enemy’s HP is 0. This AI also tends to freeze in place sometimes, but I assume that’s because other NPCs interfere with it’s pathfinding. And sometimes when enemies die, They just stop working.
I have recently tried to change my AI up by making it run on a single module.
This AI build I believe I used Y3ll0wMustangs (or whatever his name was) Zombie AI, but I heavily edited it to be compatible with my game. This code was written a long time ago, So I apologize for the messy spaghetti code.
Anyways, this is the code that focuses on finding targets, and adds them to a table of potential enemies.
Keep in mind that the coding below is all in a single module.
function Activity.FindEnemy(NPC, Torso, Root, Humanoid, Head, Traits, Angular, Events)
local dist = math.huge
local target = nil
local potentialTargets = {}
local seeTargets = {}
for i,v in ipairs(workspace:GetDescendants()) do
local human = v:FindFirstChild("Humanoid")
local torso = v:FindFirstChild("Torso") or v:FindFirstChild("HumanoidRootPart")
local TEAMFIND = v:FindFirstChild("TEAM")
local CPropsFolder = v:FindFirstChild("CharacterProperties")
if human and torso and TEAMFIND and TEAMFIND.Value ~= Traits.Team and CPropsFolder then
local DETType = CPropsFolder:FindFirstChild("Types")
if DETType and DETType:FindFirstChild("Aerial").Value == false then
if DETType and DETType:FindFirstChildOfClass("BoolValue") then
if (Root.Position - torso.Position).magnitude < dist and human.Health > 0 then
table.insert(potentialTargets,torso)
end
else
--Targets all enemies
if (Root.Position - torso.Position).magnitude < dist and human.Health > 0 then
-- print(torso.Parent.Name)
table.insert(potentialTargets,torso)
end
end
end
end
end
if #potentialTargets > 0 then
for i,v in ipairs(potentialTargets) do
if Activity.CheckSight(v, NPC, Torso, Root, Humanoid, Head, Traits, Angular) then
table.insert(seeTargets, v)
elseif #seeTargets == 0 and (Root.Position - v.Position).magnitude < dist then
target = v
dist = (Root.Position - v.Position).magnitude
end
end
end
if #seeTargets > 0 then
dist = math.huge
for i,v in ipairs(seeTargets) do
if (Root.Position - v.Position).magnitude < dist then
target = v
dist = (Root.Position - v.Position).magnitude
end
end
end
return target
end
This code block checks the NPC’s area / surroundings for enemies.
function Activity.CheckSight(Target, NPC, Torso, Root, Humanoid, Head, Traits, Angular)
-- print(Target.Position)
local ray = Ray.new(Root.Position, (Target.Position - Root.Position).Unit * 40)
local hit,position = workspace:FindPartOnRayWithIgnoreList(ray, RayPartsToIgnore)
if hit then
if hit:IsDescendantOf(Target.Parent) and math.abs(hit.Position.Y - Root.Position.Y) < 3 then
wait()
return true
end
end
return false
end
NPC Chases the enemy:
function Activity.ChaseEnemy(Target, NPC, Torso, Root, Humanoid, Head, Traits, Angular, Events)
local path = game:GetService("PathfindingService"):CreatePath()
path:ComputeAsync(Root.Position,Target.Position)
local waypoints = path:GetWaypoints()
if path.Status == Enum.PathStatus.Success then
for _, waypoint in ipairs(waypoints) do
if waypoint.Action == Enum.PathWaypointAction.Jump then
Humanoid.Jump = true
end
------------------------------------------------------------------
--Important Functions
Humanoid:MoveTo(waypoint.Position) --Moving
Activity.Attack(Target, NPC, Torso, Root, Humanoid, Head, Traits, Angular, Events) --Attacking
------------------------------------------------------------------
if Traits.LookAtEnemy == true then
Angular.Attachment1.WorldCFrame = CFrame.new(Root.Position, Target.Position)
end
------------------------------------------------------------------
if Root:FindFirstChild("BodyVelocity") then
Activity.ChaseEnemy(Target, NPC, Torso, Root, Humanoid, Head, Traits, Angular, Events)
break
end
local timeOut = Humanoid.MoveToFinished:Wait(1)
if not timeOut then
Humanoid.Jump = true
Activity.ChaseEnemy(Target, NPC, Torso, Root, Humanoid, Head, Traits, Angular, Events)
break
end
--Move Function
if Activity.CheckSight(Target, NPC, Torso, Root, Humanoid, Head, Traits, Angular) then
repeat
------------------------
Humanoid:MoveTo(Target.Position)
------------------------
--Uses transport ability if present
for _, v in pairs(Events) do
if v:GetAttribute("Type") == "Transport" then
v:Fire()
end
end
------------------------
if Target == nil then
break
elseif Target.Parent == nil then
break
end
until Activity.CheckSight(Target, NPC, Torso, Root, Humanoid, Head, Traits, Angular) == false or Humanoid.Health < 1 or Target.Parent.Humanoid.Health < 1
break
end
if (Root.Position - waypoints[1].Position).magnitude > 20 then
Activity.ChaseEnemy(Target, NPC, Torso, Root, Humanoid, Head, Traits, Angular, Events)
wait()
break
end
end
end
end
^ I believe it has something to do with this, I remember vividly adding a function where it still checks it’s sight while targetting an enemy, but It still did not work.
Another thing, I have set my NPCs torso network ownership to nil, But that seems to lag the server when there are multiple NPCs inside the workspace.
Any help is appreciated. Thanks for reading if you did
Another thing, no errors are printed either.