So I am making a Tower Defense themed game, and I want the NPC or the Tower In this case to Lock onto the closest mob, right now the Tower is locking in Order, so If I were to spawn in 4 Mobs, the Tower would only lock on to the first, than 2nd than 3rd and so on, and I really got no solution this is my method below :
> local FirstMob = nil
System.CheckRadius = function(Tower,Mob)
local MainPoint = workspace:WaitForChild("EndPoint")
local _Data = System.TowerData(Tower)
local TowerRoot = Tower:FindFirstChild("HumanoidRootPart")
local MobRoot = Mob:FindFirstChild("HumanoidRootPart")
--local Difference = (MobRoot.CFrame:toObjectSpace(TowerRoot.CFrame).p.magnitude)
local Difference = (MobRoot.Position - TowerRoot.Position).magnitude
if Difference <= _Data["Range"] / 2 then
FirstMob = MobRoot
print("In Range")
if (MobRoot.Position - MainPoint.Position).magnitude > (FirstMob.Position - MainPoint.Position).magnitude then
FirstMob = MobRoot
end
print("OK !")
Tower.Tool.Shot:Play()
System.DamageMob(_Data["Damage"],Mob)
GiveCash(Tower.Owner.Value,_Data["Damage"])
Tower:SetPrimaryPartCFrame(CFrame.new(TowerRoot.Position,FirstMob.Position * Vector3.new(1,0,1) +TowerRoot.Position * Vector3.new(0,1,0)))
wait(_Data["Rate"])
return true
end
end
System.SearchMobs = function(Tower)
local MobFolder = workspace:WaitForChild("Mobs");
for _,Mob in next,(MobFolder:GetChildren()) do
if Mob:FindFirstChild("HumanoidRootPart") then
System.CheckRadius(Tower,Mob)
end
end
end
System.RunMain = function(Tower)
while true do wait()
System.SearchMobs(Tower)
end
end
You are forgetting to check the distance from tower to all the mobs and then checking which one has a smaller distance. right now you just loop through mobs and check radius on the one and then ignore the rest of the mobs until the first one is dealt with.
Fix your CheckRadius function to not worry about a distance check. So you can rename it to Attack or something as it wont be checking radius.
Your distance check will now be in SearchMobs and will look like this:
local searchRadius = 1000 -- the tower's range
System.SearchMobs = function(Tower)
local nearestMob = nil
local distance = searchRadius
local MobFolder = workspace:WaitForChild("Mobs");
local TowerRoot = Tower:FindFirstChild("HumanoidRootPart")
if not TowerRoot then print("Tower Root Missing.") return end
for _,Mob in next,(MobFolder:GetChildren()) do
local MobRoot = Mob:FindFirstChild("HumanoidRootPart")
if MobRoot then
if (MobRoot.Position - TowerRoot.Position).magnitude < distance then
nearestMob = MobRoot -- or MobRoot.Parent
distance = (MobRoot.Position - TowerRoot.Position).magnitude
end
end
end
if nearestMob then
System.CheckRadius(Tower,nearestMob) -- should rename CheckRadius to something like "Attack"
end
end
There is a loop still, since you have to loop through all the mobs. But what I did in the example was add a distance comparison between the tower and each mob and then letting the tower deal with the mob with the shortest distance which is what your original code did not handle correctly as it was just looping through all mobs and attacking the first one it looped that was within radius of the tower but not the closest mob to the tower of all the mobs.