So I am currently working on making a zombie movement script. The purpose of this script is to get the zombie to follow the nearest player to it.
What seems to be happening is the zombie will follow one player, and then immidiately go to the next player even if they are not the nearest player to the zombie. I might be missing something very simple, but any help would be appreciated.
local hum = script.Parent.Humanoid
local humRoot = script.Parent.HumanoidRootPart
local rs = game:GetService("RunService")
local function DetermineTarget()
local nearestTarget = nil
for i,v in pairs(game.Players:GetPlayers()) do
if v.Character then
if v.Character.Humanoid.Health >= 1 then
local Distance = (v.Character.HumanoidRootPart.Position - humRoot.Position).Magnitude
if nearestTarget == nil then
nearestTarget = v
else
if (nearestTarget.Character.HumanoidRootPart.Position - humRoot.Position).Magnitude <= (v.Character.HumanoidRootPart.Position - humRoot.Position).Magnitude then
nearestTarget = v
end
end
end
end
end
return nearestTarget
end
while wait() do
local target = DetermineTarget()
if target == nil then
print("No target found")
else
hum:MoveTo(target.Character.HumanoidRootPart.Position,target.Character.HumanoidRootPart)
hum.MoveToFinished:Wait()
end
end
So it appears that the issue is that the zombie is trying to go for eveyrone in the game. I printed the target after removing the wait for movetofinished, and it spams each username in a row. It appears that it cannot determine the nearest target. How do you think I could fix this?
you need to check against the distance of the last target set to do this you can use a neerestDistance variable before you for loop like below
local hum = script.Parent.Humanoid
local humRoot = script.Parent.HumanoidRootPart
local rs = game:GetService("RunService")
local function DetermineTarget()
local nearestTarget = nil
local nearestDistance = math.huge -- sets at a very larger number. use this to make sure its closer than last target
for i,v in ipairs(game.Players:GetPlayers()) do -- i use ipairs if i rem right its abit faster
if v.Character then
if v.Character.Humanoid.Health >= 1 then
local Distance = (v.Character.HumanoidRootPart.Position - humRoot.Position).Magnitude
if Distance < nearestDistance then -- if the current player distance is less than the previous nearestDistance then set target
nearestTarget = v
nearestDistance = Distance -- set nearestDistance to new distance..
end
end
end
end
return nearestTarget
end
while wait() do
local target = DetermineTarget()
if target then -- cleaned this to not use not...
hum:MoveTo(target.Character.HumanoidRootPart.Position,target.Character.HumanoidRootPart)
hum.MoveToFinished:Wait()
else
print("No target found")
end
end
So I had to replace math.huge to 1, because it threw an error. Now, the script is just printing βNo target foundβ forever
local hum = script.Parent.Humanoid
local humRoot = script.Parent.HumanoidRootPart
local rs = game:GetService("RunService")
local function DetermineTarget()
local nearestTarget = nil
local nearestDistance = 1 -- sets at a very larger number. use this to make sure its closer than last target
for i,v in ipairs(game.Players:GetPlayers()) do -- i use ipairs if i rem right its abit faster
if v.Character then
if v.Character.Humanoid.Health >= 1 then
local Distance = (v.Character.HumanoidRootPart.Position - humRoot.Position).Magnitude
if Distance < nearestDistance then -- if the current player distance is less than the previous nearestDistance then set target
nearestTarget = v
end
end
end
end
return nearestTarget
end
while wait() do
local target = DetermineTarget()
if target then -- cleaned this to not use not...
hum:MoveTo(target.Character.HumanoidRootPart.Position,target.Character.HumanoidRootPart)
hum.MoveToFinished:Wait()
else
print("No target found")
end
end
An easier method to find the closest target is to use table.sort:
Old (Ignore)
local character = script.Parent
local humanoid = character:WaitForChild('Humanoid')
local humanoidRootPart = character:WaitForChild('HumanoidRootPart')
local targets = workspace:WaitForChild('Targets')
local alive = true
local died
died = humanoid.Died:Connect(function()
alive = nil
died:Disconnect()
died = nil
end)
while alive do
task.wait()
local near = targets:GetChildren()
local sort = function(a,b)
return (a.Position-humanoidRootPart.Position).Magnitude < (b.Position-humanoidRootPart.Position).Magnitude
end
table.sort(near,sort)
near = near[1]
print(near)
end
This would be a bit more efficient actually:
while alive do
task.wait()
local near = targets:GetChildren()
local list = {}
for _,target in pairs(near) do
table.insert(list,{Target=target,Distance=(target.Position-humanoidRootPart.Position).Magnitude})
end
local sort = function(a,b)
return a.Distance < b.Distance
end
table.sort(list,sort)
local target = list[1].Target
print(target)
end
That way it only calculates the magnitude for each target once, rather than every target per target.
βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»βΈ»
local character = script.Parent
local humanoid = character:WaitForChild('Humanoid')
local humanoidRootPart = character:WaitForChild('HumanoidRootPart')
local targets = workspace:WaitForChild('Targets')
local alive = true
local died
died = humanoid.Died:Connect(function()
alive = nil
died:Disconnect()
died = nil
end)
local sortDistance = function(a,b)
return a.Distance < b.Distance
end
while alive do
task.wait()
local near = targets:GetChildren()
local list = {}
for _,target in pairs(near) do
table.insert(list,{Target=target,Distance=(target.Position-humanoidRootPart.Position).Magnitude})
end
table.sort(list,sortDistance)
local target = list[1].Target
print(target)
end
Aside from @MightyDanthemanβs solution, your code was fine, you just needed to set the nearestDistance variable to the distance of the closest target (you were already calculating this). I also made some other changes and put some comments.
local hum = script.Parent.Humanoid
local humRoot = script.Parent.HumanoidRootPart
local rs = game:GetService("RunService")
local function DetermineTarget()
local nearestTarget = nil
local nearestDistance = math.huge -- sets at a very larger number. use this to make sure its closer than last target
for i,v in game.Players:GetPlayers() do -- you can remove pairs completely and just pass a table and it will automatically determine which is better
local character = v.Character
local humanoid = character and character:FindFirstChildOfClass("Humanoid")
if humanoid and humanoid.Health > 0 then
local Distance = (character.HumanoidRootPart.Position - humRoot.Position).Magnitude
if Distance < nearestDistance then -- if the current player distance is less than the previous nearestDistance then set target
nearestTarget = v
nearestDistance = Distance -- remember to set the nearestdistance when you set a new target
end
end
end
return nearestTarget
end
while true do
local target = DetermineTarget()
if target then -- cleaned this to not use not...
hum:MoveTo(target.Character.HumanoidRootPart.Position, target.Character.HumanoidRootPart)
hum.MoveToFinished:Wait()
else
print("No target found")
end
task.wait() -- it is bad practice to put wait() as the condition for the while loop
end