I have a module script that handles the targeting of all towers in my game, it is pretty simple:
Summary
function tower.findTarget(Tower, range, mode)
local bestTarget = nil
local bestWaypoint = nil
local bestDist = nil
local bestHealth = nil
for i, mob in ipairs(workspace.MobRealm:GetChildren()) do
if mob.Humanoid.Health > 0 then
local distToMob = (mob.HumanoidRootPart.Position - Tower.PrimaryPart.Position).Magnitude
local distToWaypoint = (mob.HumanoidRootPart.Position - workspace.Board.Player1.PlayerPath.Waypoints[mob.MovingTo.Value].Position).Magnitude
if distToMob <= range then
print(bestTarget, mode)
if mode == "Near" then
bestTarget = mob
elseif mode == "First" then
if not bestWaypoint or mob.MovingTo.Value >= bestWaypoint then
if bestWaypoint then
bestDist = nil
end
bestWaypoint = mob.MovingTo.Value
if not bestDist or distToWaypoint < bestDist then
print(mob, bestDist, distToWaypoint)
bestDist = distToWaypoint
bestTarget = mob
end
end
elseif mode == "Last" then
if not bestWaypoint or mob.MovingTo.Value <= bestWaypoint then
if bestWaypoint then
bestDist = nil
end
bestWaypoint = mob.MovingTo.Value
if not bestDist or distToWaypoint > bestDist then
bestDist = distToWaypoint
bestTarget = mob
end
end
elseif mode == "Strong" then
if not bestHealth or mob.Humanoid.Health > bestHealth then
bestHealth = mob.Humanoid.Health
bestTarget = mob
end
elseif mode == "Weak" then
if not bestHealth or mob.Humanoid.Health < bestHealth then
bestHealth = mob.Humanoid.Health
bestTarget = mob
end
end
end
end
return bestTarget
end
end
targetingEvent.OnInvoke = tower.findTarget
This is called from the tower, the target is found, then the tower continues with its animation, effects and damage.
However, no matter what mode the tower is in, it ALWAYS attacks the mega fein target when it is on the board and I can’t seem to figure out why this is happening.
Sure here is the script that handles one of my towers, they all function the same with the targeting:
Summary
local events = game:WaitForChild("ReplicatedStorage"):WaitForChild("Events")
local targetingEvent = events:WaitForChild("TargetingEvent")
local function FindBestTarget()
local target = targetingEvent:Invoke(script.Parent, config.Range.Value, config:WaitForChild("TargetMode").Value)
return target
end
while true do
local target = FindBestTarget()
if target then
local windClone = wind:Clone()
windClone.Parent = workspace
windClone.PrimaryPart.CFrame = script.Parent.Proj.CFrame
local windParts = windClone:GetChildren()
local newPosition = target.HumanoidRootPart.Position
for i, part in ipairs(windParts) do
if part:IsA("BasePart") then
local tween = TweenService:Create(part, info, {Position = newPosition})
tween:Play()
end
end
if target then
target.Humanoid:TakeDamage(calcDamage.Value)
end
game:GetService("Debris"):AddItem(windClone, .3)
if math.random(1, 100) <= calcInsta.Value then
target.Humanoid:TakeDamage(target.Humanoid.MaxHealth)
end
end
task.wait(calcSpeed.Value)
end
Basically the only thing that matters is the top where the target is determined based on the tower range and targeting mode. This function is called every time the tower fires.
But no, I can actually cycle through the modes and regardless of what mode that tower is in, it will always attack the mega fein
The tower now alternates between the front target and mega fein
EDIT:
I believe this is happening because it is targeting the mob nearest any waypoint and not the furthest waypoint, but am not sure why this isn’t being tracked with if not bestWaypoint or mob.MovingTo.Value >= bestWaypoint then
It might have to do with the increased height of the mega zombies. More height will almost surely effect the distance from the tower to the unit. You’ll want to use the position of the feet of the enemy rather than their humanoid root part.
local trueMobPos = mob.HumanoidRoot.Position - Vector3.new(0,(mob.HumanoidRoot.Size.Y/2) + mob["Left Leg"].Size.Y,0)
local distToMob = (trueMobPos - Tower.PrimaryPart.Position).Magnitude
local distToWaypoint = (trueMobPos - workspace.Board.Player1.PlayerPath.Waypoints[mob.MovingTo.Value].Position).Magnitude
What’s happening is the script is setting the MegaFein’s distToWaypoint as bestDist because it is first in the loop.
It will then go to the next target, which has a higher MovingToValue (bestWaypoint) that the MegaFein, but is further from its Waypoint than the MegaFein is from its Waypoint. Which leaves the bestDist set to the MegaFein.
I need to update the bestDist to whichever target has the bestWaypoint and is closest to that waypoint, but I don’t know how to code that.
Current script, issue takes place at if not bestDist or distToWaypoint < bestDist then:
elseif mode == "First" then
if not bestWaypoint or mob.MovingTo.Value >= bestWaypoint then
bestWaypoint = mob.MovingTo.Value
if mob.MovingTo.Value == bestWaypoint then
print("Mob and MovingTo: ", mob, mob.MovingTo.Value, "Dist and Best: ", distToWaypoint, bestDist)
if not bestDist or distToWaypoint < bestDist then
bestDist = distToWaypoint
print("dist check: ", mob)
if distToWaypoint == bestDist and mob.MovingTo.Value == bestWaypoint then
print("This should be it", mob, "MovingTo: ", mob.MovingTo.Value, "BestWaypoint: ", bestWaypoint)
bestTarget = mob
end
end
end
end
elseif mode == "Last" then
I might be misreading this, but it looks like the code doesn’t do anything if the new enemy in the loop has a higher bestWaypoint value than the current one.
elseif mode == "First" then
if not bestWaypoint or mob.MovingTo.Value >= bestWaypoint then
bestWaypoint = mob.MovingTo.Value
if mob.MovingTo.Value == bestWaypoint then
print("Mob and MovingTo: ", mob, mob.MovingTo.Value, "Dist and Best: ", distToWaypoint, bestDist)
if not bestDist or distToWaypoint < bestDist then
bestDist = distToWaypoint
print("dist check: ", mob)
if distToWaypoint == bestDist and mob.MovingTo.Value == bestWaypoint then
print("This should be it", mob, "MovingTo: ", mob.MovingTo.Value, "BestWaypoint: ", bestWaypoint)
bestTarget = mob
end
end
else --//If the bestwaypoint is higher, then there is no need to check waypoint distance.
bestTarget = mob
end
end
elseif mode == "Last" then
It actually gets checked right under mode == "First with mob.MovingTo.Value >= bestWaypoint
I just don’t know how to change the bestDist whenever a new target has a higher bestWaypoint than the target that initially set bestDist
if not bestDist or distToWaypoint < bestDist then > this doesn’t work because the bestDist is set low with the first target; bestDist needs updated before this point.
I solved this by creating a new variable checking for which waypoint bestDist what set from, and then updating bestDist if bestWaypoint is higher than that variable.
elseif mode == "First" then
if not bestWaypoint or mob.MovingTo.Value >= bestWaypoint then
bestWaypoint = mob.MovingTo.Value
if mob.MovingTo.Value == bestWaypoint then
if not bestDist or distToWaypoint < bestDist or mob.MovingTo.Value > waypointValue then
bestDist = distToWaypoint
waypointValue = mob.MovingTo.Value -- the variable that checks highest waypoint when checking bestDist
if distToWaypoint == bestDist and mob.MovingTo.Value == bestWaypoint then
bestTarget = mob
end
end
end
end
elseif mode == "Last" then