So basically, I’ve been working on this survival-type game, but I found this major problem with the ai my friend gave me. When I test with one player, it works perfectly. When I test with two, it targets the player that joined last. Another thing I noticed was it is a bit laggy. Any help would be appreciated.
Here are the two things that I think might be causing this problem:
function GetTorso(part)
local chars = game.Workspace:GetChildren()
local torso = nil
for _, v in pairs(chars) do
if v:IsA'Model' and v ~= script.Parent and v.Name == GetPlayerNames() then
local charRoot = v.PrimaryPart
if (charRoot.Position - part).magnitude < SearchDistance then
torso = charRoot
end
end
end
return torso
end
while wait() do
local enemytorso = GetTorso(hroot.Position)
if enemytorso ~= nil then
isWandering = 1
local function checkw(t)
local ci = 3
if ci > #t then
ci = 3
end
if t[ci] == nil and ci < #t then
repeat
ci = ci + 1
wait()
until t[ci] ~= nil
return Vector3.new(1, 0, 0) + t[ci]
else
ci = 3
return t[ci]
end
end
path = pfs:FindPathAsync(hroot.Position, enemytorso.Position)
waypoint = path:GetWaypoints()
oldpoints = waypoint
local connection;
local direct = Vector3.FromNormalId(Enum.NormalId.Front)
local ncf = hroot.CFrame * CFrame.new(direct)
direct = ncf.p.unit
local rootr = Ray.new(hroot.Position, direct)
local phit, ppos = game.Workspace:FindPartOnRay(rootr, hroot)
if path and waypoint or checkw(waypoint) then
if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Walk then
human:MoveTo( checkw(waypoint).Position )
human.Jump = false
end
if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Jump then
human.Jump = true
connection = human.Changed:connect(function()
human.Jump = true
end)
human:MoveTo(checkw(waypoint).Position)
else
human.Jump = false
end
hroot.Touched:connect(function(p)
local bodypartnames = GetPlayersBodyParts(enemytorso)
if p:IsA'Part' and not p.Name == bodypartnames and phit and phit.Name ~= bodypartnames and phit:IsA'Part' and rootr:Distance(phit.Position) < 5 then
connection = human.Changed:connect(function()
human.Jump = true
end)
else
human.Jump = false
end
end)
if connection then
connection:Disconnect()
end
else
for i = 3, #oldpoints do
human:MoveTo( oldpoints[i].Position )
end
end
elseif enemytorso == nil and canWander then
isWandering = 0
path = nil
waypoint = nil
--human.MoveToFinished:Wait()
end
end
in the GetTorso function, it loops through all the characters and after it does, the last torso that it scans is the one that it returns, maybe you scan all of them and add them into a table, then sort the table so that table[1] is the nearest and table[whatever number is last] is the farthest. Then pick the nearest and return that.
local table1 = {20, 15, 35, 5}
table.sort(table1, function(a, b)
return b > a
end)
print(table1[1], table1[2], table1[3], table1[4])
Output: 5 15 20 35
Use this to sort your table from lowest to highest
function GetTorso(part)
local chars = game.Workspace:GetChildren()
local torsos = {}
for _, v in pairs(chars) do
if v:IsA'Model' and v ~= script.Parent and v.Name == GetPlayerNames() then
local charRoot = v.PrimaryPart
if (charRoot.Position - part).magnitude < SearchDistance then
table.insert(torsos, {charRoot = (charRoot.Position - part).magnitude})
end
end
end
table.sort(torsos, function (a, b) return a[2] > b[2] end)
return torsos[1][1]
end
i cant really test it, but you can, so here go test it and tell me if it works.
function GetTorso(part)
local chars = game.Workspace:GetChildren()
local torsos = {}
for _, v in pairs(chars) do
if v:IsA'Model' and v ~= script.Parent and v.Name == GetPlayerNames() then
local charRoot = v.PrimaryPart
if (charRoot.Position - part).magnitude < SearchDistance then
table.insert(torsos, {charRoot, (charRoot.Position - part).magnitude})
end
end
end
table.sort(torsos, function (a, b) return a[2] > b[2] end)
print(torsos[1])
local nearest = torsos[1]
print(nearest[1])
return nearest[1]
end
you might need the full script for that, here:
if you find any other problems with it, tell me please
local SearchDistance = math.huge
local ZombieDamage = math.huge
local canWander = false
local WanderX, WanderZ = 30, 30
function getHumanoid(model)
for _, v in pairs(model:GetChildren()) do
if v:IsA'Humanoid' then
return v
end
end
end
local zombie = script.Parent
local human = getHumanoid(zombie)
local hroot = zombie.HumanoidRootPart
local zspeed = hroot.Velocity.magnitude
local pfs = game:GetService("PathfindingService")
function GetPlayerNames()
local players = game:GetService('Players'):GetChildren()
local name = nil
for _, v in pairs(players) do
if v:IsA'Player' then
name = tostring(v.Name)
end
end
return name
end
function GetPlayersBodyParts(t)
--local torso = t
--if torso then
-- local figure = torso.Parent
-- for _, v in pairs(figure:GetChildren()) do
-- if v:IsA'Part' then
-- return v.Name
-- end
-- end
--else
-- return "HumanoidRootPart"
--end
end
function GetTorso(part)
local chars = game.Workspace:GetChildren()
local torsos = {}
for _, v in pairs(chars) do
if v:IsA'Model' and v ~= script.Parent and v.Name == GetPlayerNames() then
local charRoot = v.PrimaryPart
if (charRoot.Position - part).magnitude < SearchDistance then
table.insert(torsos, {charRoot, (charRoot.Position - part).magnitude})
end
end
end
table.sort(torsos, function (a, b) return a[2] > b[2] end)
print(torsos[1])
local nearest = torsos[1]
print(nearest[1])
return nearest[1]
end
for _, zambieparts in pairs(zombie:GetChildren()) do
if zambieparts:IsA'Part' then
zambieparts.Touched:connect(function(p)
if p.Parent.Name == GetPlayerNames() and p.Parent.Name ~= zombie.Name then -- damage
local enemy = p.Parent
local enemyhuman = getHumanoid(enemy)
enemyhuman:TakeDamage(ZombieDamage)
end
end)
end
end
local path
local waypoint
local oldpoints
local isWandering = 0
if canWander then
spawn(function()
while isWandering == 0 do
isWandering = 1
local desgx, desgz = hroot.Position.x + math.random(-WanderX, WanderX), hroot.Position.z + math.random(-WanderZ, WanderZ)
human:MoveTo( Vector3.new(desgx, 0, desgz) )
wait(math.random(4, 6))
isWandering = 0
end
end)
end
while wait() do
local enemytorso = GetTorso(hroot.Position)
if enemytorso ~= nil then
isWandering = 1
local function checkw(t)
local ci = 3
if ci > #t then
ci = 3
end
if t[ci] == nil and ci < #t then
repeat
ci = ci + 1
wait()
until t[ci] ~= nil
return Vector3.new(1, 0, 0) + t[ci]
else
ci = 3
return t[ci]
end
end
path = pfs:FindPathAsync(hroot.Position, enemytorso.Position)
waypoint = path:GetWaypoints()
oldpoints = waypoint
local connection;
local direct = Vector3.FromNormalId(Enum.NormalId.Front)
local ncf = hroot.CFrame * CFrame.new(direct)
direct = ncf.p.unit
local rootr = Ray.new(hroot.Position, direct)
local phit, ppos = game.Workspace:FindPartOnRay(rootr, hroot)
if path and waypoint or checkw(waypoint) then
if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Walk then
human:MoveTo( checkw(waypoint).Position )
human.Jump = false
end
if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Jump then
human.Jump = true
connection = human.Changed:connect(function()
human.Jump = true
end)
human:MoveTo(checkw(waypoint).Position)
else
human.Jump = false
end
hroot.Touched:connect(function(p)
local bodypartnames = GetPlayersBodyParts(enemytorso)
if p:IsA'Part' and not p.Name == bodypartnames and phit and phit.Name ~= bodypartnames and phit:IsA'Part' and rootr:Distance(phit.Position) < 5 then
connection = human.Changed:connect(function()
human.Jump = true
end)
else
human.Jump = false
end
end)
if connection then
connection:Disconnect()
end
else
for i = 3, #oldpoints do
human:MoveTo( oldpoints[i].Position )
end
end
elseif enemytorso == nil and canWander then
isWandering = 0
path = nil
waypoint = nil
--human.MoveToFinished:Wait()
end
end
The reason it says this is because when you are the only person in the game and you just join it, the script is already running while your character isnt loaded in yet, which means it just errors.
You can solve this by putting a pcall function, which skips errors and keeps the code running.
for the GetTorso() function put this:
function GetTorso(part)
local chars = game.Workspace:GetChildren()
local torsos = {}
for _, v in pairs(chars) do
if v:IsA'Model' and v ~= script.Parent and v.Name == GetPlayerNames() then
local charRoot = v.PrimaryPart
if (charRoot.Position - part).magnitude < SearchDistance then
table.insert(torsos, {charRoot, (charRoot.Position - part).magnitude})
end
end
end
table.sort(torsos, function (a, b) return a[2] > b[2] end)
pcall(function()
print(torsos[1])
local nearest = torsos[1]
if nearest[1] ~= nil then
print(nearest[1])
return nearest[1]
end
end)
end
and for the loop do this:
while wait() do
pcall(function()
local enemytorso = GetTorso(hroot.Position)
if enemytorso ~= nil then
isWandering = 1
local function checkw(t)
local ci = 3
if ci > #t then
ci = 3
end
if t[ci] == nil and ci < #t then
repeat
ci = ci + 1
wait()
until t[ci] ~= nil
return Vector3.new(1, 0, 0) + t[ci]
else
ci = 3
return t[ci]
end
end
path = pfs:FindPathAsync(hroot.Position, enemytorso.Position)
waypoint = path:GetWaypoints()
oldpoints = waypoint
local connection;
local direct = Vector3.FromNormalId(Enum.NormalId.Front)
local ncf = hroot.CFrame * CFrame.new(direct)
direct = ncf.p.unit
local rootr = Ray.new(hroot.Position, direct)
local phit, ppos = game.Workspace:FindPartOnRay(rootr, hroot)
if path and waypoint or checkw(waypoint) then
if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Walk then
human:MoveTo( checkw(waypoint).Position )
human.Jump = false
end
if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Jump then
human.Jump = true
connection = human.Changed:connect(function()
human.Jump = true
end)
human:MoveTo(checkw(waypoint).Position)
else
human.Jump = false
end
hroot.Touched:connect(function(p)
local bodypartnames = GetPlayersBodyParts(enemytorso)
if p:IsA'Part' and not p.Name == bodypartnames and phit and phit.Name ~= bodypartnames and phit:IsA'Part' and rootr:Distance(phit.Position) < 5 then
connection = human.Changed:connect(function()
human.Jump = true
end)
else
human.Jump = false
end
end)
if connection then
connection:Disconnect()
end
else
for i = 3, #oldpoints do
human:MoveTo( oldpoints[i].Position )
end
end
elseif enemytorso == nil and canWander then
isWandering = 0
path = nil
waypoint = nil
--human.MoveToFinished:Wait()
end
end)
end
It should work, if it doesn’t, reply to this message.
Thats because i sent the wrong version
this one should be working
local SearchDistance = math.huge
local ZombieDamage = math.huge
local canWander = false
local WanderX, WanderZ = 30, 30
function getHumanoid(model)
for _, v in pairs(model:GetChildren()) do
if v:IsA'Humanoid' then
return v
end
end
end
local zombie = script.Parent
local human = getHumanoid(zombie)
local hroot = zombie.HumanoidRootPart
local zspeed = hroot.Velocity.magnitude
local pfs = game:GetService("PathfindingService")
function GetPlayerNames()
local players = game:GetService('Players'):GetChildren()
local name = nil
for _, v in pairs(players) do
if v:IsA'Player' then
name = tostring(v.Name)
end
end
return name
end
function GetPlayersBodyParts(t)
--local torso = t
--if torso then
-- local figure = torso.Parent
-- for _, v in pairs(figure:GetChildren()) do
-- if v:IsA'Part' then
-- return v.Name
-- end
-- end
--else
-- return "HumanoidRootPart"
--end
end
function GetTorso(part)
local chars = game.Workspace:GetChildren()
local torso = nil
for _, v in pairs(chars) do
if v:IsA'Model' and v ~= script.Parent and v.Name == GetPlayerNames() then
local charRoot = v.PrimaryPart
if (charRoot.Position - part).magnitude < SearchDistance then
torso = charRoot
end
end
end
return torso
end
for _, zambieparts in pairs(zombie:GetChildren()) do
if zambieparts:IsA'Part' then
zambieparts.Touched:connect(function(p)
if p.Parent.Name == GetPlayerNames() and p.Parent.Name ~= zombie.Name then -- damage
local enemy = p.Parent
local enemyhuman = getHumanoid(enemy)
enemyhuman:TakeDamage(ZombieDamage)
end
end)
end
end
local path
local waypoint
local oldpoints
local isWandering = 0
if canWander then
spawn(function()
while isWandering == 0 do
isWandering = 1
local desgx, desgz = hroot.Position.x + math.random(-WanderX, WanderX), hroot.Position.z + math.random(-WanderZ, WanderZ)
human:MoveTo( Vector3.new(desgx, 0, desgz) )
wait(math.random(4, 6))
isWandering = 0
end
end)
end
while wait() do
local enemytorso = GetTorso(hroot.Position)
if enemytorso ~= nil then
isWandering = 1
local function checkw(t)
local ci = 3
if ci > #t then
ci = 3
end
if t[ci] == nil and ci < #t then
repeat
ci = ci + 1
wait()
until t[ci] ~= nil
return Vector3.new(1, 0, 0) + t[ci]
else
ci = 3
return t[ci]
end
end
path = pfs:FindPathAsync(hroot.Position, enemytorso.Position)
waypoint = path:GetWaypoints()
oldpoints = waypoint
local connection;
local direct = Vector3.FromNormalId(Enum.NormalId.Front)
local ncf = hroot.CFrame * CFrame.new(direct)
direct = ncf.p.unit
local rootr = Ray.new(hroot.Position, direct)
local phit, ppos = game.Workspace:FindPartOnRay(rootr, hroot)
if path and waypoint or checkw(waypoint) then
if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Walk then
human:MoveTo( checkw(waypoint).Position )
human.Jump = false
end
if checkw(waypoint) ~= nil and checkw(waypoint).Action == Enum.PathWaypointAction.Jump then
human.Jump = true
connection = human.Changed:connect(function()
human.Jump = true
end)
human:MoveTo(checkw(waypoint).Position)
else
human.Jump = false
end
hroot.Touched:connect(function(p)
local bodypartnames = GetPlayersBodyParts(enemytorso)
if p:IsA'Part' and not p.Name == bodypartnames and phit and phit.Name ~= bodypartnames and phit:IsA'Part' and rootr:Distance(phit.Position) < 5 then
connection = human.Changed:connect(function()
human.Jump = true
end)
else
human.Jump = false
end
end)
if connection then
connection:Disconnect()
end
else
for i = 3, #oldpoints do
human:MoveTo( oldpoints[i].Position )
end
end
elseif enemytorso == nil and canWander then
isWandering = 0
path = nil
waypoint = nil
--human.MoveToFinished:Wait()
end
end