How intelligent do the zombies need to be? How avanced are the motorskills of the zombies?
Is humanoid relevant?
Common things people do is that on the servers, the zombies are simple blobs(single part) and then they render them on the client. Also finite-state-machines are pretty useful in the scenario of AI’s having to possess different behaviours and states that are local to the AI.
Pathfinding? Roblox’s pathfinding is very very good at what it is supposed to do… Maybe not in this case though. They’re expensive. Very expensive. A* pathfinding is very common nowadays, perhaps read into that. But you’re on the right track when you’re thinking of calculating and tweening zombies’ movements.
BUT… again,… This question has been asked a couple of dozen times and all of your questions are answered by those predecessors. So… next time look for a bit longer.
Raycasting sounds like a pretty good solution, however I would add that if the Y axis different is more than a character’s height pathfinding service is automatically used because in that case the AI usually needs to find a hill/ledge/stairs anyway. Raycasting is much, much faster and much less costly than pathfinding with Roblox’ engine for both.
Depending on what kind of map layout you have, you can get pretty creative with the pathfinding. If your map is a single building, you can subdivide it into “sectors”, each being cubic regions inside it, representing e.g. rooms. From there on you can make zombies always pathfind into sectors where players are in, and once they share a sector with a player you’re almost guaranteed that a follow or raycast path will make the zombie attack the player, eliminating latency where it actually matters for user experience (“Zombies shouldn’t get stuck when they’re literally two studs next to me”).
As I previously stated. This has been asked a lot of times. I am aware that we are not the stackoverflow community, but it is quite common to be sharked for asking redundant questions. I am just saying… One search and you wouldn’t have to have asked this question.
Should there be a group of zombies in close proximity you could have them follow the same path. This will give a good hoard effect and will also mean less paths are being created.
Of course if they are grouped up there is a chance that they will push each other, but personally I think for a brainless zombie hoard it would just add to it.
I would want to achieve something similar to some of the top games about zombies near the front page, whilst maintaining high performance even with hundreds of zombies. When joining these games I usually don’t see more than 30 zombies active at one point.
Ideally my zombies can move towards players and use pathfinding to get around obstacles that block them. I’d assume a humanoid isn’t 100% needed but would be simply an easier solution (just using humanoid:MoveTo and pathfinding provided by Roblox)
I have heard of this method mentioned before on the server, and I recall these single part zombies being controlled by a humanoid on the server. I can get my head around rendering the zombie on the client but I’m not sure how I can control a single part using a humanoid, not something I’m very informed on. Finite state machines are something I haven’t considered, I may research more on that relating to NPC behaviour!
If I recall correctly I need to set up nodes across the server to use A* pathfinding, though is this a viable solution if I were to have multiple changing maps (a round based type of game) that are decently large?
I’m sorry, I know this question has been asked a lot but a lot of the solutions I have either tried (a lot of humanoid related optimizations) or I don’t understand. I was hoping for responses that could be explained in a different way to help me understand the methods behind stuff like controlling one part on the server.
I’ve seen a lot of these posts and for a lot of them I wasn’t sure how to implement some of the stuff mentioned.
On one post I read something helpful about calculating the distance between a zombie and a player to determine how long to wait until I next check over players and their distance away from the zombie. Though I only check every 5 seconds, and I don’t think that would be the cause of lag.
I’ve also read a helpful post on optimizing humanoids, but most of the strategies I already used (disabling states) and some I didn’t know how to do (tweening an anchored torso to positions is easy on a flat map, but a map requiring jumps seems harder to do)
Sorry again for the repetitive thread, but thanks for the advice! Finite state machines seem interesting to learn about
Dividing the map sounds interesting! I’m not sure how viable it would be if I were to have this zombie automatically respond to any type of map though (for example if I was making a round based game and creating maps on the go)
Checking the Y axis difference makes sense though and I’ll keep this in mind, thanks!
There are many ways to handle this, but the solutions are small, mainly because the server is lagging, not the client. I’d say to create a oop humanoid and check for garbage using collectgarbage.
edit: handling frameworks, damage, and etc will slow down the client
a direct example is cb at close quarters with enemy.
if it’s with the client however, and you did all these steps it is clearly a different story.
edit2: aka making the orientation, and position going towards the player is not that hard.
I wasn’t aware of this, I’ll see if I can understand anything from it to help me!
Dynamic A* pathfinding does sound complex, I’ll see if I can find any ways to implement it effectively.
Ah ok! I’m assuming using bodyforce would automatically cause the zombie to move up hills (and not clip into them) when moving straight, the jumping is the only thing I was confused on, but I have advice on this thread on how to do that so maybe I wont need humanoids after all
Oh ok, and I will respond to old ones in the future, I see where I went wrong with making another thread that re-iterates a lot of what has been already said. Thank you again for your responses and advice!
I now understand what you are trying to accomplish, one thing to keep in mind is that games like ‘zombie strike’ , ‘Zombie attack’ and ‘zombie rush’ do not have pathfinding.
So if you are using path finding for a lot of zombies there will be performance issues.
Keep in mind that long paths will cause more strain. So moving zombies that are far away is a good idea.
Also. dont forget that the players will be moving so it may be that paths need to be recalculated every so often.
edit:
I replied to the wrong person again.
heres a tag so it pings you @Superdexus
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.