Alrighty, so I’ve been looking into making NPCs for my game for a while now, but I’ve been putting it off as it’s pretty well known that this is arguably one of the most complex topics you could probably deal with on this platform. Given that no NPC systems are interchangeable between games since every game has different systems, (Unless there’s some open sourced NPC framework that I’m not aware of) you’ll ultimately have to make your own.
But, since I’ve never done that before, I’m curious as to how games normally handle NPC’s. I’m pretty sure it’s almost a certainty that each of these systems is a tailor made OOP monster of a task to undertake. Since to my understanding, making optimized NPC’s that can interact with a game’s systems without tanking the games performance, is pretty difficult.
I’m mainly asking as to how these systems work usually. Pathfinding is something I can understand as there are plenty of resources on using pathfinding such as SimplePath, but how exactly is pathfinding dealt with when per say, an NPC is targetting an entity within the workspace. Is the path constantly updated every frame? And while they’re pathfinding, are they constantly checking for other factors through conditional logic? That’s what I would assume but given a complex enough game I would imagine this being an absolute bomb on performance.
Actual actions aren’t much of a concern for me though. The framework I’m using, WCS, makes it pretty easy to initiate actions on both clients and NPCs, so the divide between server and player inputs isn’t a concern.
But overall, I cannot comprehend how bigger games are able to make high quality NPC’s with unfathomably complex logic without it being a hinderance to performance. There are plenty of games without crazy NPC logic, like Blox Fruits for example, but I’m leaning towards the quality of my NPC’s, as well as how you even handle decision making.
The best example I can think of is Deepwoken’s massively complex NPC’s which are pretty impressive, and the server can handle tons of them. (In general I find deepwoken to be a technical herculean feat for several reasons, but the NPC’s are one of the most impressive things I’ve found within it.)
I’ve been thinking about this too, I still don’t have an answer. I assume they render on the client obviously and handle position and authenticate actions like attacking on the server. They definitely use behavior trees but I still don’t know how they use animation events on the client for hitboxes, in fact I’m not sure how they replicate animations at all if NPCs are client sided.
I’ll have to look into it a lot more, but if you figure anything out let me know, I am also interested in making NPCs similar to theirs.
Creating NPCs is not that difficult if you have experience.
The Pathfinding Module (or your own Pathfinding system) is used for movement.
Optimization:
You can load animations via FireClient, for all players that are in the vicinity. I think Deepwoken has such a system, because it greatly reduces the load on the server as the animations are handled by the clients.
You can create a hitbox, in which the scripts in the NPC will be active, provided that the player is in the Hitbox zone.
The same as 1, but all VFX, effects and other visuals do 1 way, so that players who are far away do not process information and visuals.
I can’t give any other advice, because you didn’t say what kind of NPC you need to make
Place the NPC in the server’s camera to prevent replication, this should free up most of the memory used. A part in the server’s workspace is used to represent their humanoid root parts cframe. The part does not change its cframe unless the client requests it to do so.
Create a pseudo character on the client that will respond to the part’s cframe property changing.
If a client is within a certain maximum radius of the part and has the part in their viewport or if the part is in a minimum radius have the client invoke an unreliable remote event which will update the part’s cframe to the character’s root part on the server. This will also render the character, otherwise the character will be hidden.
The character on the client can use pathfinding to reach the part. Clients will detect the cframe change of the part and update their local npcs to that position only if that part is within the maximum radius.
If I’m not mistaken this should be a fullproof way of reducing NPC’s lag and memory use drastically while retaining the benefit of having the real NPC on the server.
Seems like a lot of hurdles need to be crossed in order to get ‘smart’ npcs that are also optimized. I’ve heard that using actors can help with running constant NPC logic, but I don’t know how accurate that is.
Its honestly not even script activity that is a problem for me when having a high NPC count, its just having 30 unanchored models constantly moving, the replication of unanchored parts is honestly the biggest hinderance of making my game so far. This is a very frustrating dilemma but it should be very rewarding to the game’s performance if a solution is found.
I do know this for sure though, running complicated logic for NPCs on the server has barely had any impact on performance in comparison to replicating the changes.
I found a great thread on this topic that retains the benefit of seeing changes on the server by placing the NPCs in the server’s camera so they don’t replicate, having clients visualize the NPCs, and then using a module that will run code on the client for the fake NPC and on the server for the real NPC. I’ve been working on a resource to do this.
On the client it updates the cframe as long as the cframe object value changes, it also runs separate logic for culling animations and making NPCs invisible based off of range as well. This reduces lag by cutting out all rendering and only replicating a cframe without remotes only if certain conditions are met, this seems to be the best that ROBLOX will allow. The module has a method that lets you load a modulescript whose logic will run on the server and client and passes the respective NPC parameter.
This should make it to where I can at least have 100 mobs in a server at a time and it will still run smoothly even with NPC logic still running on the server. To have the radius logic run smoother I’ll look into using actors, I plan on just whitelisting tagged NPCs to a spacial query but even running this once per second only when the player is moving around, seems like it would be bad practice? Any thoughts?