AI Code Review [Feedback]

Made an AI that chases you and attacks you when near, what I’m looking for:
• Optimizations
• Situations where it would break
• Making it smarter
The AI scans the workspace for the nearest player and goes to them, it computes a path and heads to the path. If the player has moved from the path it computes another path and eventually ends up killing the player.

PathFindingService = game:GetService("PathfindingService")
Grab1 = script.Parent.Humanoid:LoadAnimation(script.Grab)
Grab2 = script.Parent.Humanoid:LoadAnimation(script.Grab2)
function AttackFunction(TargetCharacter)
	local RandomAnimation = math.random(1,2)
	if RandomAnimation == 1 then
		Grab1:Play()
		wait(.5)
		TargetCharacter.Humanoid:TakeDamage(25)
	else
		Grab2:Play()
		wait(.5)
	TargetCharacter.Humanoid:TakeDamage(25)
	end
end
function FindNearest()
    local lowest = math.huge 
    local NearestPlayer = nil
    for i,v in pairs(game.Players:GetPlayers()) do 
        if v.Character then
			local position = script.Parent.HumanoidRootPart.Position
            local distance = v:DistanceFromCharacter(position)
           	if distance < lowest then
                lowest = distance
                NearestPlayer = v
            end
        end
    end
	if NearestPlayer == nil then
		wait()
		FindNearest()
	end
    local path = PathFindingService:CreatePath()
	local HumanoidRootPart = script.Parent.HumanoidRootPart
	local TargetCharacter = NearestPlayer.Character
	path:ComputeAsync(HumanoidRootPart.Position,TargetCharacter.HumanoidRootPart.Position)
	if path.Status == Enum.PathStatus.Success then
	     wayPoints = path:GetWaypoints() 
	else
		wait()
		FindNearest()
	end
	print("computing waypoint")
	for i,v in pairs(wayPoints) do
		print("going to waypoints")
		 script.Parent.Humanoid:MoveTo(v.Position)
		    if v.Action == Enum.PathWaypointAction.Jump then
                script.Parent.Humanoid.Jump = true
            end
		local MoveToWait = script.Parent.Humanoid.MoveToFinished:Wait(1)
		if not MoveToWait then
	        script.Parent.Humanoid.Jump = true
			break
		end
		if (HumanoidRootPart.Position - TargetCharacter.HumanoidRootPart.Position).Magnitude <= 5 and TargetCharacter.Humanoid.Health > 0 then
			AttackFunction(TargetCharacter,HumanoidRootPart)
			print("near player")
		end
	end
	while (HumanoidRootPart.Position - TargetCharacter.HumanoidRootPart.Position).Magnitude <= 5 and TargetCharacter.Humanoid.Health > 0  do wait()
		print("target player found before loop restarted")
		AttackFunction(TargetCharacter,HumanoidRootPart)
	end
	FindNearest()
end
FindNearest()
4 Likes

One optimization you can do is utilize raycasting to avoid generating a path.

Computing a path is expensive. Like, seriously expensive. And that delay for it’s computation can really bug out with an AI that tries to compute a path frequently.

function module:ComputeSmart()
local pathfindingNeeded = true
local rayHit,rayPosition = self:RayTo(self.TargetedAsset.HumanoidRootPart)
if rayHit then
	if rayHit:IsDescendantOf(self.TargetedAsset) then
		pathfindingNeeded = false
		self:MoveToPoint(rayPosition)
	end
end
if pathfindingNeeded then
	self.currentWaypointIndex = 1
	self.currentlyPathing = true
	self.activeMap = self.queueMap[1]
	if self.Path then self.Path:Destroy() end
	self.Path = PathfindingService:CreatePath()
	self.Path:ComputeAsync(self.MobAsset.HumanoidRootPart.Position,self.queueMap[1])
	local waypoints = {}
	
	if self.Path.Status == Enum.PathStatus.Success and #waypoints >= 2 then
		waypoints = self.Path:GetWaypoints()
		self.currentWaypointIndex = 2
		self:MoveToPoint(waypoints[self.currentWaypointIndex].Position)
	else
		self:MoveToPoint(self.MobAsset.HumanoidRootPart.Position)
	end

end

end

1 Like

Never used metatables, or self, how would I apply this?

You can ignore the metatables and self part of that code, I’m just demonstrating some potential logic.

It assumes pathfinding is needed (pathfindingneeded=true) then it will cast a ray. if the ray can make contact with the target you want, and isn’t obstructed, then just move the humanoid. otherwise, we will compute a path.

that is the basic sense of that logic.

Something like this?

	local ray = Ray.new(HumanoidRootPart.Position,TargetCharacter.HumanoidRootPart.Position)
	local part, position = workspace:FindPartOnRay(ray,TargetCharacter and HumanoidRootPart.Parent, false, true)
	if part then
		if part:IsDescendantOf(TargetCharacter) then
			HumanoidRootPart.Parent.Humanoid:MoveTo(position)
			return FindNearest()
		end
	end

yeah, and then if it doesn’t moveto, then you can go about computing paths.