Optimize targeting system

https://gyazo.com/bbc1696e2bda2cee8777c7428bc09930?token=67f2262697023fd2ffa8a7988e3f6a96
100 units on the field and the script activity is 33%, are there any better ways to script this?

You should try to remove the while wait() do by an event or something.

Yeah I replaced wait() with a wait(2), that dropped the script activity down to 2%. But thats still too much for only 100 units that arent moving, shooting, or being animated

Could you paste your script? You should also use events, and also use task.wait(n) instead. If using events isn’t possible, you should increase the task.wait(n) time higher, because unless you need really fast reacting enemies, it seems good.

while wait(2) do
	for i,v in pairs(game.Workspace.AISoldiers:GetChildren()) do
		if v.Info.Target.Value == nil then
			local Zombie
			for i,zin pairs(game.Workspace.Zombies()) do -- gotta get all the enemies
				if (z.HumanoidRootPart.Position - v.PrimaryPart.Position).magnitude <= v.Info.MaxRange.Value then
					local Closest = 100000
					local Distance = (z.HumanoidRootPart.Position - v.PrimaryPart.Position).magnitude
					if Distance < Closest then
						Closest = Distance
						Zombie = z
					end
				end
			v.Info.Target.Value = Zombie
			end
		end
	end
end

changed it up a bit… now it just shoots at the closest enemy and now it dosnt search for enemies after already finding one, which will drop the script activity down to 0% but when they’re searching its still at 2%.

Try changing your script to this:

--//Variables
local AISoldiers = workspace.AISoldiers
local Zombies = workspace.Zombies

--//Functions
local function InitializeSoldier(soldier)
	local targetValue = soldier:WaitForChild("Info"):WaitForChild("Target")

	local function SetTarget()
		if not targetValue.Value then
			local nearestZombie = nil
			local nearestDistance = math.huge

			for i, Zombie in ipairs(Zombies:GetChildren()) do
				local distance = (Zombie.HumanoidRootPart.Position - soldier.PrimaryPart.Position).Magnitude

				if distance < nearestDistance then
					nearestDistance = distance
					nearestZombie = Zombie
				end
			end

			targetValue.Value = nearestZombie
		end
	end
	
	SetTarget()
	
	targetValue:GetPropertyChangedSignal("Value"):Connect(function()
		SetTarget()
	end)
end

for i, AISoldier in ipairs(AISoldiers:GetChildren()) do
	InitializeSoldier(AISoldier)
end

AISoldiers.ChildAdded:Connect(function(AISoldier)
	InitializeSoldier(AISoldier)
end)

This singlehandedly dropped the script activity by like 30%, (1.6% → 1.2%) but I had to add in some of the things you missed. In this script the soldiers check the map once with an infinite range then stop.

--//Variables
local AISoldiers = workspace.AISoldiers
local Zombies = workspace.Zombies

--//Functions
local function InitializeSoldier(soldier)
	local targetValue = soldier:WaitForChild("Info"):WaitForChild("Target")

	local function SetTarget()
		if not targetValue.Value then
			local nearestZombie = nil
			local nearestDistance = math.huge

			for i, Zombie in ipairs(Zombies:GetChildren()) do
				local distance = (Zombie.HumanoidRootPart.Position - soldier.PrimaryPart.Position).Magnitude
				if distance <= soldier.Info.MaxRange.Value then -- searches for zombies in range

					if distance < nearestDistance then -- closest zombie out of all the zombies in range
						nearestDistance = distance
						nearestZombie = Zombie
					end
				end

				targetValue.Value = nearestZombie
			end
		end
	end

	SetTarget()

	targetValue:GetPropertyChangedSignal("Value"):Connect(function()
		SetTarget()
	end)
end

while wait(2) do -- check frequently
	for i, AISoldier in ipairs(AISoldiers:GetChildren()) do
		InitializeSoldier(AISoldier)
	end
end

AISoldiers.ChildAdded:Connect(function(AISoldier)
	InitializeSoldier(AISoldier)
end)

That still dropped script activity from an average of 1.6% to 1.2% which is still too high the amount of units I have on the field (64 soldiers, 256 zombies)
The main source of activity is the nested loop
– Loops through all soldiers (64 loops)
– Then each soldier loops through the entire bug folder, even the bugs that are miles away (64 * 256 = 16384)

You shouldn’t run a loop to initialize the soilders multiple times. Just run that for i, loop once and it should be good.

The zombies will be out of range when it runs, then it wont run again. That’s why it has to keep on checking through a loop.

Then add the loop inside the SetTarget function while checking the value. The way you did it is connecting hundreds of functions that you aren’t disconnecting.

Your script activity is happening cause of loops within loops, stop looping through all of them and just save an array of the zombie models and just loop through those each time.

You can also just create a sphere part representing the range and use zone plus so theres no while wait() do but that might be tedious.

But how’d I compare the distance of the zombies in that array to the soldiers?

You’d make a map relation between them all if you are looking to optimize time complexity at the cost of space complexity.