i recently wrote my own very basic like Zombie AI where the only thing it does is follow the closest player using the function :MoveTo and allowing to have some sounds, however while it is functional, if i try to put in more zombie AI, it ends up starting to lag more and more, at least 30 will cause the entire game to lag.
i’ve noticed that the amount of received data is ridiculously high after actually using the zombie AI, so i definitely know its coming from there. i use a runService loop RenderStepped to do some of this. (i get around 30 fps from playing this, which is a high decrease from 120)
so how do i optimize the zombie AI’s loop? i would appreicate some help.
I AM ALREADY AWARE OF PATHFINDINGSERVICE, HOWEVER I DO NOT WANT THE ZOMBIES TO BE THAT SMART. I ONLY WANT THE ZOMBIES TO JUST CONSTATNLY FOLLOW A PLAYER AND HAVE BASIC AI.
here’s some scripting i’ve done so far
function findClosestCharacter()
local closestPlayer = nil
local closestCharacter = nil
local closestCharacterDistance = nil
for _, player in players:GetPlayers() do
if not player.Character then continue end
local characterPosition = player.Character.PrimaryPart.Position
local NPCPosition = character.PrimaryPart.Position
local distance = (characterPosition - NPCPosition).Magnitude
if not closestCharacter then
closestPlayer = player
closestCharacter = player.Character
closestCharacterDistance = distance
continue
end
if distance < closestCharacterDistance then
closestPlayer = player
closestCharacter = player.Character
closestCharacterDistance = distance
end
end
if closestPlayer and players:FindFirstChild(closestPlayer.Name) and closestPlayer.Character then
target = closestCharacter
character.PrimaryPart:SetNetworkOwner(closestPlayer)
end
end
function moveToSpot(part)
if part then
humanoid:MoveTo(part.Position)
end
end
function steppedLoopForAI(timeSinceConnected, deltaTime)
tick_findNextPlayerTime += deltaTime
tick_zombieSoundsTime += deltaTime
if target then
moveToSpot(target.PrimaryPart)
end
if tick_findNextPlayerTime > findNextPlayerTime then
tick_findNextPlayerTime = 0
findClosestCharacter()
end
if tick_zombieSoundsTime > zombieSoundsTime then
tick_zombieSoundsTime = 0
zombieSoundsTime = math.random(2, 5)
playZombieSound()
end
end
If you want to improve bandwidth usage, here is undoubtedly one of my top 10# favorite threads of all time!
This post goes very in-depth on how you could optimize your network usage.
i run this function pretty much every frame, the function to check for the nearest player is done every 5 seconds but im pretty sure the :MoveTo function is whats causing a lot of the hassle of load
i’ll take a look at the video, thanks! from face value, it would basically separate the :MoveTo function into different threads (CPUs im thinking) so that it can reduce the load i’m guessing? i’ll update this soon with my attempt on implementing multithreading
this was an interesting post to read but it doesn’t exactly have all the things i’d want as the move function is i’m pretty sure the culprit for all the issues, i don’t actually move the parts through CFraming nor any of that, i just use a basic function although i will definitely keep this post for the future, thanks for sharing!
it turns out :MoveTo function itself is not safe in parallel and from microprofiling my game i find that the time for physics simulation and worker stuff is pretty large:
(this is when i have like 50 zombies running at once)
i’m not sure on how to begin with fixing these long frame times, if anyone could help.
only mathematical operations can be done in parallel operations, it is not possible to do physical operations, including :MoveTo, because you are physically executing the npc. instead of scanning every frame, you can make the npc scan every second. this will only be to find the player. after detecting the player, follow the player with a loop until the player leaves the detection area. you can use repeat until or while for this. you can use a lower number instead of 1 second in the follow-up loop, for example, running the :MoveTo Function every 0.05 seconds.
also multithreaded the renderstepped loop itself until it has to do all the physical operations
disabled a bunch of humanoid states
eventually i’ll probably have to reimplement their movement (cause i wanna make a wave system) by controlling it through one server scripted loop instead which should help not run through 100 renderstepped loops at once
it doesn’t have the best performance with 100 zombies, but with 50 it’s pretty respectable so it’s good
the ragdolling system is pretty much the only issue where if theres too many of the “ragdoll death” script running at once it just starts lagging the player again
thanks guys! multithreading was def interesting to learn abt