This is a very arduous method of pathfinding. There are two ways I would approach this, the more efficient way and the advanced but not-fit-for-this-context-way.
METHOD 1: The efficient way
Logically, a turret can only shoot one zombie at a time, which is the closest zombie. So there is no reason to sort the entire array just to find one closest zombie. So instead of sorting every zombie, simply write an algorithm to loop through Zombies
and return the closest one:
local Zombies = {}
function findLegibleTorsos()
-- deletes the old array
Zombies = {}
-- constructs the new array of Zombies
for i,v in pairs(game.Workspace:GetChildren()) do
if v:IsA("Model") and v:FindFirstChild("ZombieRootPart") ~= nil then
local torso = v:FindFirstChild("ZombieRootPart")
if (torso.Position - mainpart.Position).magnitude <= range then
Zombies[#Zombies + 1] = v -- appends the zombie to the end of the array
end
end
end
end
function findNearestTorso()
-- loops through the entire array and returns the closest zombie
local closestZombie = Zombies[1]
local closestRange = (closestZombie.ZombieRootPart.Position - mainpart.Position).magnitude
for i = 2, #Zombies do -- start at the 2nd index so the first zombie doesnt check itself
local zombie = Zombies[i]
local range = (zombie.ZombieRootPart.Position - mainpart.Position).magnitude
if range < closestRange then
closestZombie = zombie
closestRange = range
end
end
return closestZombie.ZombieRootPart
end
METHOD 2: Your way, but better
Looking at your code, my first instinct was to introduce you to the table.sort()
function’s custom sort function parameter. It can easily perform exactly what your script does in simpler terms. Let me brief you:
local array = {4, 2, 1, 3}
table.sort(array) -- sorts from least to greatest by default
print(table.unpack(array)) -- 1 2 3 4
Now looking a bit closer, table.sort()
actually has a second parameter, the sort function. You can make the sort function however you like. For example, you can make it sort in descending order instead.
table.sort(array, function(a, b) -- b is the value at the index directly after a
-- a and b are in the right spot when this is true
return a > b -- a is in the right spot when it's greater than the next value
end)
print(table.unpack(array)) -- 4 3 2 1
Now, using this custom function, we can actually sort by property of an object. In this case, we should sort the zombies based on how close their Position property is to other character’s
local Zombies = {}
function findLegibleTorsos()
-- deletes the old array
Zombies = {}
-- constructs the new array of Zombies
for i,v in pairs(game.Workspace:GetChildren()) do
if v:IsA("Model") and v:FindFirstChild("ZombieRootPart") ~= nil then
local torso = v:FindFirstChild("ZombieRootPart")
if (torso.Position - mainpart.Position).magnitude <= range then
table.insert(Zombies, v) -- appends the zombie to the end of the array
end
end
end
end
function findNearestTorso()
-- sorts the array based on zombie proximity in order of closest to farthest
table.sort(Zombies, function(a, b)
return (a.ZombieRootPart.Position - mainpart.Position).magnitude < (b.ZombieRootPart.Position - mainpart.Position).magnitude
end)
return Zombies[1].ZombieRootPart -- because the closest zombie is always the first on the list
end
Personally, I would use the findLegibleTorsos()
function every frame to update the turret’s radar. so I would put the sort in that function. But the code above does everything your old code did in a much simpler fashion rather than holding 2 arrays and indexing by magnitude. In addition, you should never set keys that are prone to duplicates. If 2 zombies are exactly 2 studs away, the 2nd one would have overwriten the other zombie, potentially erroring your code.
Edit: sorry about this, but I realized that findLegibleTorsos()
stores the torsos on your version, while it sorts the zombie models in mine. I edited the findNearestTorso()
function so it would work though.