How to fully optimize zombies?

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.

2 Likes

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.

2 Likes

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)

8 Likes

Thank you for your response!

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

1 Like

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.

1 Like

This makes sense, I can see why it would be quicker to check from the player instead of each zombie

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.