You could create 1 script that manages all the zombies to make life easier.
You can use coroutines for a lot of it. Its not a must have but In terms of getting the information other zombies have it is much easier.
Coroutines can be ended as well so if you wanted to break seperate functions down for the zombies you could.
then all information like existing paths could be fed into tables.
If done properly it isnt really a issue.
So long as has properly been fed the correct information and variables that is.
I get where you coming from but if you learned how to use them effectively then you would understand where im coming from.
In no way are coroutines suitable for everything, but when creating multiple objects / models running mostly simple scripts it poses no problem. e.g projectiles
This isnt exactly a coroutine thread so lets not go off topic.
As @Ukendio said, donât reinvent the wheel. Stick with humanoids, do research on finite-state machines and build off of that.
You had some great ideas in your original post (raycasting to determine whether pathfinding is necessary; disabling unused humanoid states; etc), and I want to add onto this list with literally anything I can think of that might affect performance:
Donât leave any threads hanging or unnecessary connections active
Might seem obvious, but I canât emphasize how critical this is if youâre employing coroutines frequently across 100 different NPCs. Donât leave anything hanging.
Avoid Robloxâs built-in hit detection
Itâs horrendous. Robloxâs own hit detection is notoriously bad and you shouldnât use it under any circumstances, especially on a large scale like what youâve described. Alternatives to this include using Region3 (better, but not the best) and using raycasting. Do research here and use whatever works bestâjust avoid the built-in methods like the plague.
Be clever with spawning / despawning NPCs
If your map is big, consider using selective spawning / despawning based on certain conditions to take some weight off of the server. Is there a zombie thatâs way out of range of players? Can any players actually see the zombie at this current time? Despawn the zombie, and thatâs one less NPC that the server has to deal with.
Use Network Ownership
I donât feel qualified enough to talk about the pros/cons of network ownership, since thereâs a lot I donât entirely understand about itâincluding potential security issues it may bring, if any exist. That said: look into network ownership and see if there are ways you can take advantage of it, because Iâm (almost) certain that it will help.
I saw something on this thread (my thread was linked here) about dividing a map. I experimented with this a little bit to improve performance; however, the major bottleneck with Humanoids is often still network replication, which wonât be improved by improving script performance.
Map is divided into 100x100 stud areas, analogous to quadtrees. Zombies and players track which âgridâ theyâre currently in at all times. (Simple comparison of 3D position, you probably want to put them in multiple âareasâ if theyâre right on the border). Iâm not sure how big an âareaâ should be, this should be experimentally determined depending on map size etc.
Raycasting is an excellent alternative to pathfinding if you believe thereâs a good chance thereâs going to be a line of sight (e.g. close by). However, this means that you need to consider that there could be other zombies impeding the âline of sightâ, while the zombie still can walk straight to the player, which mandates putting other zombies into the raycast ignore list.
So raycast performance improvements can involve:
When youâre raycasting the direct path to the target, the ignore list only needs to include zombies in the same 100x100 grid area. (This could easily cut your ignore list from 300 NPCs to 10, which is a decent performance improvement).
Clearly, avoid raycasting if thereâs a significant distance to the target (say >5 seconds of travel time) because thereâs a high probability that there wonât be a direct path.
Raycast pathfinding pitfall: Itâs possible for there to be a direct line of sight to the target, however following this direct line of sight causes the zombie to fall down. I encountered this very niche issue when zombies tried to follow players on bridges across raised areas, so if this is something your game has, raycast downwards along the line of site to check for any falls. (Extra performance cost, donât do this if itâs not necessary, but my map was a little crazy).
Pathfinding improvement performances can include:
For each zombie, youâre probably iterating through every player, and choosing the closest one. You can decrease distance magnitude checks by first only checking players which are in the same 100x100 stud area as the zombie. If there are none, check all the other players. (If your grids are too small, however, it might cause weird problems where players in other grids are actually closer; therefore youâll have to think about this a little bit, but it was one of my ideas!)
Then you need to think about how youâre going to detect zombies attacking the player, which probably means more raycasts!
My implementation of this was actually done backwards. Instead of each zombie individually raycasting to see if their attack worked, I did raycasting from the perspective of the player. If there are zombies in the same 100x100 area as the player, then the player raycasts does 4-6 raycasts around their torso in a circle, checking to see if there are any zombies that could successfully attack them. Unless you have a lot of players, this is less performance heavy than raycasting from every single zombie to its target when itâs nearby! The raycasts were also very short in distance and had no ignore list = very quick. May need special considerations if different zombs have different attack ranges.
That also allowed for very nice and âcentralisedâ lag-correction calculations for attack detection; I only needed to do the calculation for lag compensation once for every player (when I was batching their attack detection), not for every single zombie.
These ideas were all relatively successful.
I think Roblox was working on a new Humanoid system which is meant to be very modular - when this is released (if it hasnât already), Iâd look at trying to use their logic for humanoid movement. Then you can put accurate humanoid physics behavior into a non-humanoid NPC, which should allow for a lot more control over what gets replicated to the client (which I found was the real problem!) However, the caveat is that it might run really slowly when doing maths in Lua for hundreds of NPCs, so weâll just have to see.
Note that if you have a simple and non-dynamic map, you could fare better by using a custom pathfinding algorithm or potentially custom NPCs from the beginning (and interpolation on the client). I got a mediocre physics system working for customs NPCs which wasnât to slow, but Roblox pathfinding was too uncustomisable for a dynamic map.
Good luck! NPCs are fun to work on, but very limited Roblox systems and limited/misinformative documenting on pathfinding = lots of experimentation.
P.S. set network owner to nil if you havenât done so already, avoids weird bugs and stuttering when the server tries to swap around network ownership (was an issue in late 2019)
A grid system could potentially work, Iâve never tried out anything to do with dividing maps into sections so itâll be interesting to experiment with (Iâve got a lot of experimenting to do as you mention at the bottom of your post!)
I was thinking of creating a folder in the workspace to hold all the zombies, I was unaware having a large ignore list could cause much of a performance impact? (If so I have to go and optimize a few of my scripts!)
Iâve messed around with projectiles before and managed to make a high performance system for them; I would be raycasting around up to 400 times per frame with very little performance impact (these raycasts were also very short, which I know are very inexpensive) A few raycasts every few frames checking for jumps doesnât seem in my mind to be much of an impact on performance (my map will have a lot of gaps and I had not realised this would be happening). Iâll be able to see whether this is bad for performance with many zombies and will adjust from there through experimenting with new methods.
Iterating through players within a grid also sounds like a good way of improving performance; my game wont have more than 30 players and Iâm thinking of using another method mentioned using distance calculations to time when I really need to check for a new player next or not.
I hadnât thought of doing it like this, sounds like a very good way of doing it, thanks for the advice!
Iâm definitely also anticipating the new and more optimized humanoids as well to see how they compare to current humanoid performance and functionality.
I was not aware of this, I heard that clients having network ownership of npcs/zombies helps with replication lag, maybe Iâm misinformed?
Thank you again! Iâll keep all this in mind while developing!
I might be misremembering , but just try it at some point to experiment. I think automatic network ownership was causing weird teleporting/stuttering issues for me + I needed to do some physics on zombies which was even glitchier with network replication
If this sounds a bit weird, I think it was also helpful because it allowed me to reduce the polling rate for comparing the distance of players from zombies (for attacks / target choosing). It sounds a bit counter intuitive looking back, but was helpful in my case.
Generally, assigning network ownership shouldnât be deemed scary. Not particularly exploitable if the server decides where to puts a zombieâs network ownership. Just by default donât let the clients claim ownership of it.
Thanks for the clarificationâI thought as much but wasnât 100% sure that it wouldnât create vulnerabilities, and didnât want to give firm advice that would do so.