Need help detecting the nearest enemy

So I have been working on a tower defense game, everything has been going smooth up until I start working on the towers.

Just like any TD game enemies spawn in and follow a path which I have working perfectly, now I just need to work on the towers.

The tower I have been working on uses a for loop to search through the SpawnedEnemies folder and determines the magnitude between the tower and the enemies PrimaryPart, the issue is the script pauses longer than it should between each shot and after dealing damage to around 10 enemies the script breaks completely stating that “HumanoidRootPart is not a member of Enemy”

So two issues arise 1. Only detect PrimaryPart for X amount of time 2. Shots are delayed longer than the wait timers.

Here is the code that I currently have written

while wait(2) do

local TD = script.Parent.Parent.Parent.TDWorld
local Tower = script.Parent
local Enemies = TD.SpawnedEnemies:GetChildren()

for i, v in pairs(Enemies) do
  if v.HumanoidRootPart and v.Humanoid.Health >0 then
  local mag = (Tower.Position - v.HumanoidRootPart.Position).Magnitude
  	if mag <30 and v.Humanoid and v.Humanoid.Health >0 then
  		
  		script.Parent.TargetAtt.CFrame = v.Body.CFrame
  		v.Humanoid:TakeDamage(5)
  		wait(0.1)
  		script.Parent.TargetAtt.Position = script.Parent.TowerAtt.Position
  		wait(1)
  	end	
  end
end

end

You have waits in the for loop, so the wait is delaying it every time. Instead try

for i, v in pairs(Enemies) do
  if v.HumanoidRootPart and v.Humanoid.Health >0 then
  local mag = (Tower.Position - v.HumanoidRootPart.Position).Magnitude
  	if mag <30 and v.Humanoid and v.Humanoid.Health >0 then
  		spawn(function()
  		script.Parent.TargetAtt.CFrame = v.Body.CFrame
  		v.Humanoid:TakeDamage(5)
  		wait(0.1)
  		script.Parent.TargetAtt.Position = script.Parent.TowerAtt.Position
  		wait(1)
       end)
  	end	
  end
end
  1. Your shots delayes because you have putted wait function inside loop 2 times. Assuming the second wait function is a fire rate so it must look something like that:
wait(0.1) 
script.Parent.TargetAtt.Position = script.Parent.TowerAtt.Position
wait(0.9)  --1 - 0.1 = 0.9
  1. You setting TowerAtt position to it’s same position. Create new variable for old position:
local oldPos = script.Parent.TargetAtt.Position

--loop code

script.Parent.TargetAtt.Position = oldPos
  1. v.Part isn’t a way to check if object exists. Do this:
if v:FindFirstChild("object name") and etc then
      --your code here
end
  1. Im assuming that tower is a model and so model doesn’t have property called position so you must get tower’s hrp position:
local mag = (Tower.HumanoidRootPart.Position-v.HumanoidRootPart.Position).magnitude
  1. Checking humanoid health second time isnt good idea.
if mag < 30 then
      --code
end

In the end it should look something like this:

local TD = script.Parent.Parent.Parent.TDWorld
local Tower = script.Parent
local oldPos = Tower. TargetAtt.Position
while wait(2) do

local Enemies = TD.SpawnedEnemies:GetChildren()

for i, v in pairs(Enemies) do
  if v:FindFirstChild("HumanoidRootPart") and v:FindFirstChild("Humanoid") 
and v.Humanoid.Health >0 then
  local mag = (Tower.HumanoidRootPart.Position - v.HumanoidRootPart.Position).Magnitude
  	if mag <30 then
  		
  		script.Parent.TargetAtt.CFrame = v.Body.CFrame
  		v.Humanoid:TakeDamage(5)
  		wait(0.1)
  		script.Parent.TargetAtt.Position = oldPos
  		wait(0.9)
  	end	
  end
end
end