Articles/Moving NPCs Between Points|Moving NPCs Between Points tutorial, you learned about direct straight-line character movement. In this article, we’ll explore how to move an NPC along a more complex path or around obstacles. This is known as pathfinding.
In Roblox, pathfinding is driven by the
PathfindingService, so your scripts must get the service before doing much else.
Creating a Path
Once you’ve included
PathfindingService in your script, you can create a new
Path with the
As you can see, this method accepts one argument,
pathParams, a Lua table which lets you fine-tune the path for the size of the agent (the humanoid that will move along the path).
Here are the available parameters for the
|AgentRadius||integer||2||Humanoid radius. Used to determine the minimum separation from obstacles.|
|AgentHeight||integer||5||Humanoid height. Empty space smaller than this value, like the space under stairs, will be marked as non-traversable.|
|AgentCanJump||boolean||true||Sets whether off-mesh links for jumping are allowed.|
Moving Along the Path
The zombie below has a few more brains than the zombie in the
Articles/Moving NPCs Between Points|direct movement tutorial, so it shouldn’t walk directly toward the pink flag and into the lava. Instead, let’s make it walk safely across the plank.
The following code gets the
PathfindingService, creates variables for the zombie and its
Humanoid, sets the destination point (pink flag), and creates the
PathfindingService/CreatePath|CreatePath()because the agent (zombie) is a normal-sized character and the default radius/height values are fine.
Computing the Path
After you’ve created a valid
Path object using
PathfindingService/CreatePath|CreatePath(), you need to compute the path — this is an explicit step that does not happen automatically when the path is created!
To compute a path, call
Path/ComputeAsync|ComputeAsync() on the
Path object, providing a
Vector3 for both the starting location and target destination.
Getting Path Waypoints
Path is computed by
Path/ComputeAsync|ComputeAsync(), it will have a series of waypoints that, when followed, can lead a character along the path. These points are gathered with the
With the waypoints saved, we can show each one by creating a small part at its location:
As you can see, the path waypoints lead across the plank and over to the pink flag.
The path looks good, so let’s make the zombie walk along it. The easiest way is to call
Humanoid/MoveTo|MoveTo() from waypoint to waypoint. In this script, we can simply add two commands to the same waypoint loop:
Handling Blocked Paths
Many Roblox worlds are dynamic — parts might move or fall, floors collapse, etc. This can block a computed path and prevent the NPC from reaching its destination.
To handle this, you can connect the
Path/Blocked|Blocked event to the
Path object and re-compute the path around whatever blocked it. Consider this pathfinding script:
Several things have been added or changed, so let’s walk through the code:
- The first section is similar to before: get the
PathfindingService, set some variables, and create the
Pathobject. The main additions are the
waypointswill store the computed waypoints and
currentWaypointIndexwill track the index number of each waypoint the zombie reaches, starting at 1 and increasing as it walks along the path.
- The next function,
followPath(), contains many of the same commands we used earlier, plus a little error checking on line 21. If
Path/ComputeAsync|path:ComputeAsync()is successful, we get the waypoints and store them in the
waypointsvariable. Next, we set the
currentWaypointIndexcounter to 1 and move the zombie to the first waypoint.
- In a dynamic place where paths may be blocked, it’s problematic to loop through all waypoints in a
pairs()loop. If anything blocks the path, that loop can be tricky to stop/break. In this script, the
onWaypointReached()function moves the zombie onward only after the next waypoint is reached.
- The final function,
onPathBlocked(), is connected to the
Path/Blocked|Blockedevent on line 49. If the path is ever blocked, this function will fire and
blockedWaypointIndexwill be the waypoint index number that was blocked.
Path/Blocked|Blockedevent can fire on a path anytime during the path's lifetime. It may also fire multiple times if moving obstacles are involved, like a boulder rolling across the path. Because of this, you may want to
Instance/Destroy|destroythe path or un-register the
Path/Blocked|Blockedconnection until a new path is computed.
As you can see,
PathfindingService lets you create NPCs that are much smarter than the average zombie. Along with custom agent parameters and the
Path/Blocked|Blocked event, you can make any NPC reach a destination, even in a dynamic and changing place.