I have no idea, I’m still trying to figure out how you manage to maintain 60 FPS with 3000 NPCs with Roblox Humanoid while most of the DevForum members would recommend to not use Roblox Humanoid and Rendering Characters on the Client.
So let me get this right;
You are using Only Roblox Humanoid with R6 rigs with most States disabled and RootPart Anchored and you can maintain 3000 NPCs at 60 FPS with no other special gimmick?
My hypothesis is that with 3000 NPCs you’ll have a total of at least 21000 (3000x7) parts
Roblox struggles while handling 500 moving sphere parts at once so moving all of those NPCs at once would be too much for the Engine (in extreme cases)
So if you have a Max cap of 150 moving NPCs at once that’s 1050 (150x7) parts max at any given moment
Since you are using a Humanoid few parts are forced to be CanCollide = true, although most of the NPCs aren’t moving thus Anchored.
So if you want to have 10000 NPCs which is 70000 (10000x7) parts, you should figure out if Roblox can handle at least 70000 parts in a game in a small space
If you don’t mind me asking what is your computer’s spec?
I believe that Computer’s specs plays a role but I would say that Roblox Studio has it’s limits and inefficiencies so theoretically you could have a Super Computer but Roblox Studio might not be able to perform above it’s limits.
The zombies are handled on the client.
On the server I have 2 parts with a humanoid welded together (Torso and Head, nothing more), the client renders the arms, legs, etc and does the animations.
the humanoid has ALL states disabled except Dead and Running(NoPhysics).
And zombies that are not moving or active are anchored, I check their velocity and then anchor and set them inactive if they aren’t doing anything and unachored when actively doing something. That’s how I did it.
3000 NPCs worked even.
Edit: Oh oops hadn’t read.
I play on a pretty decent gaming laptop.
Has about 16 GB RAM, Intel core i7 (Quad) and a Nvidea GTX 1050.
Back to humanoids.
Humanoids really aren’t that bad as some may think.
What really causes most lag is physics and unused states such as climbing (which does a lot of raycasts just to see if it can climb a ladder).
I literally only use states I actually need, I even disable the jumping state if not needed and the ragdoll state.
Only Dead and Running are enabled.
I get around 35 FPS with 13 HumanoidStates Disabled and 27 FPS without any HumanoidStates Disabled for 250 NPCs moving around without Animations played while also using CollisionGroups to disable collisions between all of the NPCs, however some NPCs will Teleport if I SetNetworkOwner to nil (Server).
Although from doing some testing at 200 NPCs Disabling HumanoidStates and Collision doesn’t make any difference but does when going beyond 200+ NPCs
These are full Server-Sided NPCs nothing is done on the Client.
I have made a system without using a Humanoid nor Parts on the Server-Side and maintained 40 FPS with 400 NPCs moving and animated at once in a 512, Y, 512 space, goes back to 60 FPS when they stop moving
That honestly is strange.
Im not entirely sure why I can run 1500 NPCs and you only 250.
it’s a experiment I did and results turned out to be better than I actually expected.
Maybe it’s so optimized because I literally use 1 single script to run 1500 NPCs?
I have a table containing all NPC.
When a NPC spawns I do
npcs[npc].mainfunction = function()
--I do my stuff here
end
--Then I do this.
spawn(npcs[npc].mainfunction)
That way I could run 1500 NPCs with 1 single script.
Take a good look at the code I posted, that’s literally the entire AI.
Just quickly looking through your code, you seem to be creating new threads for no reason at all.
Both of your delays are unneeded as they’re at the end of another thread anyways, so it wouldn’t block any code from executing. 2/3 spawns also do this. Any connection will run on another thread, unless you actually have multiple things that need to run you don’t need to create new threads in this case.
I’m also using only one Script to control all of the NPCs, although they are Server-Sided.
Don’t forget that they are R15 Rigs so that’s twice the amount of Parts of a R6 Rig
I took at look at your Script several times, you are doing quite a few things differently than the place I linked but I can see that the major performance gain is from anchoring RootParts.
While using one script can be performant, I can see that even though you are using 1 script to control all of the NPCs they have their own Threads.
So again, if you want to run 10000 NPCs we’ll have to answer the question of whether or if Roblox can handle 70000 anchored parts in any given space.
How big is that space shown in the OP?
I’m going to assume that it’s bigger than 2048, Y, 2048
When talking about ur pc specs, you should really include clock speeds for Processor and GFX Card. He has a 2.9GHz processor, which is most likely why his pc struggles. I personally won’t buy anything with less than 4GHz
I remember watching crazyman32 do a similar approach to this before for his game but rendering only visible NPCs. I think he managed to get over 1500 NPCs at 60 FPS, but I’m not too sure on the NPC count. If I find the video I’ll link it.
So as AMD said, you could render only visible NPCs, as well as distant ones (basically any that is shown on screen). Don’t really see a use case for rendering non visible ones.
If it isn’t processing power, what else could limit NPCs?
I personally think it’s mostly physics and such that limit NPCs.
But don’t really know what to optimize futher.
I actually want more NPCs to move at the same time.
I kind of limited the amount of NPC that are allowed to move at the same time to prevent all 1500 of them to move at the same time.
I don’t think it’s possible at this time to achieve that but until Roblox Upgrades it’s Software and Server-Hardware to be more performant and/or powerful you are stuck with it’s current limits.
We don’t have the technology yet basically, or more accurately Roblox.
Oh, alright.
3000 NPCs was the highest I’ve tested but noticed that 1500 is more stable.
The server can handle 3000 NPCs, however for patato PCs 1500 NPCs already is pretty heavy.
NPCs are rendered clientside mostly, the server only does hitboxes, targetting, movement, thinking in general, etc.
I made AI for 1500 NPCs and there is no lag at all (they are cubes)
so i think having alot of NPCs will only lag your game because of the amount of parts not because they are humanoid or AI
The two scripts that control them only have 2-3% script activity altogether.
I don’t think it’s the parts mainly.
Mainly physics and hit boxes/touch events that make it laggy.
I was wondering…
Is there a way to turn off the touched event for parts so NPCs touching each other won’t trigger it?
But players and ray-casts hitting the parts should still work.
I could do a lot with that knowledge.
I’ve heard of collision service but never used it before in all honestly.
Even my current 1K AI game doesn’t use collision service.
The NPCs quite literally just use a few parts and a lot is rendered client side. Touched events are still triggered when they hit each other.
Have you tried shifting network ownership of npcs close to players?
It could take some of the physics load off of the server, since the players would be handling physics instead of the server.
I haven’t thought about that actually.
But wouldn’t this result in really choppy movement if the NPCs target suddenly switched on a laggy server?
But I’ll keep this in mind, thank you, perhaps this could help a lot in games
that need to handle a lot of zombies at once.
If I can make a full functional, hyper-optimized zombie AI
and have 2000 zombies walk around I could perhaps make a game
like Deadrising in Roblox.
I’d be cool to have players literally bulldoze through tons of zombies with vehicles or weapons, I’m pretty excited about that idea.
I recommend adding an LOD system (Total war games), as player doesn’t need to see all the NPCs, only a fraction of them. What you could do is create “Squads” where you load the NPC data into some array and when player gets close enough or will see the “Squad” soon enough just load it back in. The squads are NPC in themselves but are invisible to the player and have no reference in the world space, but they also move in it. This will allow for much larger simulations and could be useful in other projects where there are huge battles between thousands of units.
Also adding max AI decisions per tick is a good practice too (Ravenfield uses that)! You basically iterate over some value of NPCs per heartbeat and make decisions for them and then wait for another heartbeat so the cycle can repeat but on other zombies. Of course you have to iterate over all of the NPCs but this change itself will make up for the performance. You can also set priority of those AI units based on how close they are to the players. Roblox has also special function called BulkMoveTo, you really should check it out as it can improve the performance even more.