15 min

In the 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 PathfindingService/CreatePath|CreatePath() method:

Path Parameters

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 pathParams table:

Key Value Type Default Description
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 Path object.

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

Once the 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 Path/GetWaypoints|GetWaypoints() function:

Showing Waypoints

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.

Path Movement

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:

  1. The first section is similar to before: get the PathfindingService, set some variables, and create the Path object. The main additions are the waypoints and currentWaypointIndex variables. waypoints will store the computed waypoints and currentWaypointIndex will track the index number of each waypoint the zombie reaches, starting at 1 and increasing as it walks along the path.
  1. 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 waypoints variable. Next, we set the currentWaypointIndex counter to 1 and move the zombie to the first waypoint.
  1. 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.
  1. The final function, onPathBlocked(), is connected to the Path/Blocked|Blocked event on line 49. If the path is ever blocked, this function will fire and blockedWaypointIndex will be the waypoint index number that was blocked.

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.

  • npc
  • path
  • pathfinding