quick TL;DR:
I am using an OOP approach to handle the behavior of enemy npcs. In each NPC object, a state is stored which defines that particular NPC’s behavior. When a player is close enough, the npc’s state changes from “Idle” to “Pursuit”. When the NPC is in “Pursuit”, the NPC will use pathfinding service and humanoid:MoveTo() to chase the player. If a player leaves the range of the npc, it will go back to the “Idle” state. I can get this roughly working when everything is server side, but I want to compute the pathfinding on the client side of any players that close enough to see the npc. Pathfinding and using Humanoid:MoveTo() on the server is way too encumbering and laggy.
What I am looking for: I want to know an effective way to handle the pathfinding and humanoid:MoveTo() on the client. How do i do this so that when an npc chases a player, the npc’s position is updated for all players that can see the npc? I don’t just want to move the enemy npc on one client. I figure it has something to do with setting the NetworkOwner of the npc model, because the server needs to know when the enemy gets close enough to attack the player. My initial reaction is to use lots of remote events to update the server on the npc’s position, but I don’t know how I can ensure things don’t get wonky.
Example of what I have now:
I would try using a RemoteFunction to return the path and then move the NPC. Would that work?
Trying to use remote events in this situation may be more trouble than it’s worth. The only way I can think of doing this would be picking a single player to do the pathfinding calculations locally, fire a remote to the server, which then would run code to follow that path (This also would create a vulnerability where clients could pass garbage pathfinding data to the server).
The biggest problem with that approach, besides the security vulnerability, is that the use of Remote Events would cause replication lag which would probably be worse than what you are already experiencing.
I can only guess because I have no code to look at, but I assume your “Pursuit” loop is something similar to the following pseudocode:
for i, waypoint in pairs(waypoints) do
if playerHasMoved() then
recalculatePath()
break
else
agentHumanoid:MoveTo(waypoint.Position)
agentHumanoid.MoveToFinished:Wait()
end
end
If this is the case, the problem likely lies in the MoveToFinished:Wait()
line (or any similar waiting method). I would suggest running the :MoveTo()
and MoveToFinished:Wait()
in a coroutine that can be stopped whenever the agent has to recalculate its path.
You can also do what Roblox did in their “Character Pathfinding” documentation example. They avoided using a loop altogether and opted to handle agent movement exclusively via connections.
In my experience, I find the pathfinding system to be very performant, capable of handling path recalculations each frame. Whenever I had a problem similar to yours, it came down to me fixing my waiting logic.
I hope this helps and you can get that NPC moving buttery smooth! 