NavigationPathQueryResult3D in Godot – Complete Guide

Pathfinding is a central feature in many games and simulations, allowing characters to navigate through complex environments. Godot Engine provides robust tools to implement such systems, and with the release of Godot 4, comes an updated way to handle 3D pathfinding: the NavigationPathQueryResult3D class. This element of Godot’s toolkit represents the result of a 3D pathfinding query, and mastering it can open new possibilities for your projects. Let’s dive into the world of pathfinding and discover how this class can enhance your game development skills.

What is NavigationPathQueryResult3D?

The NavigationPathQueryResult3D class is a part of Godot 4’s navigation system, specifically designed for 3D environments. It’s an object you’ll often interact with when working with pathfinding queries. This class houses the output from 3D navigation queries, providing valuable information such as the path points, regions, and links navigated.

What is it for?

Imagine characters in a game needing to find their way from point A to point B, avoiding obstacles and taking the shortest possible route. The NavigationPathQueryResult3D class steps in to hold the data you’ll need after requesting a path from the NavigationServer3D. It’s essentially a roadmap provided to your game characters, enabling them to move intelligently within the virtual world.

Why should I learn it?

Understanding the NavigationPathQueryResult3D is crucial for creating dynamic and believable movement in 3D game environments. By learning how to use this class, you will be able to:
– Implement efficient pathfinding algorithms in your games.
– Customize navigation paths based on game mechanics.
– Enhance AI for non-player characters to provide better player experiences.

As you harness this powerful tool, you’ll unlock the ability to create more immersive and interactive 3D worlds, elevating your game design to new heights. Let’s embark on this journey and explore the capabilities that NavigationPathQueryResult3D has to offer.

CTA Small Image

Retrieving a Path Using NavigationPathQueryResult3D

Before we dive into the code examples, let’s first initialize our NavigationServer3D and prepare our environment for pathfinding. The following code snippet illustrates how to create a NavigationServer3D and set up a simple navigation mesh:

var nav_server :=
var nav_mesh_instance :=

# Set up the navigation mesh (usually loaded or created in the editor)

# Add the NavigationMeshInstance to the NavigationServer3D
var nav_mesh_rid = nav_mesh_instance.get_rid()
nav_server.navmesh_add(nav_mesh_instance, GlobalTransform())

# Create the query
var path_query_result := nav_server.map_create_path(0, Vector3(0, 0, 0), Vector3(10, 0, 10), true)

In the above example, the `map_create_path` method is used to create a path from the origin `(0, 0, 0)` to the destination `(10, 0, 10)` on the navigation mesh layer `0`. The result of this method is stored in the `path_query_result` variable, which is an instance of NavigationPathQueryResult3D.

Accessing Path Points

Once we have obtained our `path_query_result`, we can access the computed points along the path. The following code snippet demonstrates how to iterate through the points of the path:

for i in range(path_query_result.get_point_count()):
    var point = path_query_result.get_point(i)
    print("Point ", i, ": ", point)

If you need to obtain all the points at once, you can do so with the `get_path()` method:

var path_points = path_query_result.get_path()
for point in path_points:
    print("Path Point: ", point)

These points represent the physical locations on the navigation mesh where the character or object should travel in sequence to follow the path.

Analysing Path Data

With `NavigationPathQueryResult3D`, you can also access additional data about the path, such as the regions and links, which can be useful for more complex navigation setups. The following snippets illustrate how to retrieve this information:

# Obtaining regions traversed by the path
var regions = path_query_result.get_regions()
for region in regions:
    print("Region: ", region)

# Obtaining links between regions
var links = path_query_result.get_connections()
for link in links:
    print("Link from Region ", link.from_id, " to Region ", link.to_id)

The regions refer to specific navigation areas, while the links are connections between these areas. These can be essential for games with multilevel navigation.

Handling Path Changes

When using dynamic environments where obstacles can appear or disappear, understanding how to update paths is essential. You can perform a new path query and reassign the `path_query_result` when changes in the environment occur. Here’s how you would handle such a scenario:

# Assuming an obstacle has been added or removed, recomputing the path
var new_path_query_result = nav_server.map_create_path(
    path_query_result.get_point(0),  # Start from the current start
    Vector3(10, 0, 15),  # New endpoint or changed due to the obstacle

# Reassign the path_query_result with new path data
path_query_result = new_path_query_result

# Now, you can use the updated `path_query_result` as before

This allows you to adapt the pathfinding dynamically to the current state of the game world, ensuring that your characters can always find their way.

Stay tuned for the next part of our tutorial, where we’ll delve into more advanced features and provide you with additional code examples to bolster your understanding of the NavigationPathQueryResult3D class in Godot 4.Continuing with our exploration of the NavigationPathQueryResult3D in Godot 4, let’s delve deeper into the advanced features that this class offers. These features can give you precise control over how characters or objects navigate through your game world.

Advanced Pathfinding Features

One of the powerful aspects of Godot’s pathfinding system is the ability to fine-tune the behavior of your paths. This includes optimizing the path, dealing with dynamic obstacles, and reacting to changes in the game’s environment. Let’s take a closer look at these features with some practical code examples.

Optimizing Paths
Path optimization can reduce the number of points in a path, simplifying the movement and reducing computational overhead. When the path has been created, you can call methods to optimize the path before using it:

var path = path_query_result.get_path()
nav_server.path_smooth(path, 0.5)  # `0.5` is the amount of smoothing

for point in path:
    print("Optimized Path Point: ", point)

Dynamic Obstacle Avoidance
If you have moving obstacles in your game, you can update the NavigationMesh to reflect these changes and then recalculate the path:

# Let's say you have moved some obstacles, you'd need to bake the
# navigation mesh again to take these into account.

# After updating the navigation mesh, create a new path query.
path_query_result = nav_server.map_create_path(nav_mesh_rid, Vector3(0, 0, 0), Vector3(10, 0, 10), true)

Reacting to Environment Changes
In dynamic environments, it’s often necessary to monitor and update paths as the environment changes. You might want to do this in response to events, like a door opening or closing:

# Responding to an event, such as a door opening
if door_opened:
    # Invalidate the old path

    # Assume we have a new nav mesh for the open door scenario
    nav_mesh_rid = nav_mesh_instance.get_rid()
    nav_server.navmesh_add(nav_mesh_instance, GlobalTransform())

    # Recalculate the path with the door open
    path_query_result = nav_server.map_create_path(nav_mesh_rid, Vector3(0, 0, 0), Vector3(10, 0, 10), true)

Dealing with Multi-level Navigation
For games with multiple floors or elevation changes, it’s essential to handle vertical movement:

# Assume we have an elevator or ramp connecting two floors.
# Here we need to connect two different navigation meshes:

var floor1_nav_mesh_rid = floor1_nav_mesh_instance.get_rid()
var floor2_nav_mesh_rid = floor2_nav_mesh_instance.get_rid()

# Connect the nav meshes at the points where the elevator or ramp is
nav_server.connect_navmeshes(floor1_nav_mesh_rid, floor2_nav_mesh_rid, elevator_position)

Customizing Path Points

You also have the ability to inject your own custom logic into the path points, allowing for an even greater level of customization:

# Example custom logic to add a detour
var custom_path = []
for i in range(path_query_result.get_point_count()):
    var point = path_query_result.get_point(i)
    # Custom logic to add a detour for each point
    if i == 1:  # Add a detour at the second point
        custom_path.append(point + Vector3(2, 0, 2))

# Now custom_path contains the original path plus your detour

These examples illustrate just a fraction of the power and flexibility that the NavigationPathQueryResult3D class provides in Godot 4. By understanding and utilizing these advanced features, you can create more responsive and complex navigation behaviors. Whether you’re creating a sprawling open-world adventure or a tightly controlled puzzle game, mastering 3D pathfinding with NavigationPathQueryResult3D will greatly enhance the player’s experience.

And remember, if you’re ever feeling overwhelmed or need guidance, we at Zenva are here to help. Our comprehensive courses can take you from a curious beginner to a confident game developer, one step at a time.As we dive further into the capabilities of the NavigationPathQueryResult3D class in Godot 4, let’s explore even more code examples and information that will help you revolutionize your game’s navigation system.

Handling Path Failure

In certain scenarios, the pathfinding query might fail, possibly due to there being no valid path from the start to end location. It’s important to handle this case to prevent your game characters from behaving unexpectedly:

var path_query_result = nav_server.map_create_path(nav_mesh_rid, Vector3(0, 0, 0), Vector3(10, 0, 10), true)
if path_query_result.status == NavigationServer3D.PATH_SUCCESS:
    # Use the path_query_result as intended
    print("Pathfinding failed!")
    # Handle the failed pathfinding attempt

Adding Cost to Path Points

Sometimes, you might want certain areas of your game to be less desirable for characters to traverse. You can simulate this by adding a cost to path points, which the pathfinding algorithm will consider:

# Here's how you could adjust the cost for different points
var path_cost_map = {Vector3(5, 0, 5): 10.0, Vector3(6, 0, 5): 15.0}  # Example costs for specific points
var path = path_query_result.get_path()
var adjusted_path = []

for point in path:
    var cost = path_cost_map.get(point, 1.0)  # Default cost is 1.0
        "position": point,
        "cost": cost
# Process the adjusted path with respective costs

Altering the Path in Real-time

For truly dynamic gameplay, you might want to alter the path as the character moves along it. Maybe there’s an obstacle that suddenly moves or the player creates a new barrier. The following code reacts to such changes in real-time:

# Detect if an obstacle has appeared on the path
var obstacle_detected = is_obstacle_at_point(character.get_global_transform().origin)

if obstacle_detected:
    # Quickly find an alternative path
    path_query_result = nav_server.map_create_path(nav_mesh_rid, character.get_global_transform().origin, target_position, true)
# Update character movement using the new path_query_result

Continuous Path Updating for Moving Targets

In some scenarios, such as when pursuing a moving target, path updates need to be continuous to ensure efficient chasing behavior:

# Assuming 'target' is the moving character we are following
var target_position = target.get_global_transform().origin
var path_update_timer = 0.0

func _process(delta):
    path_update_timer += delta
    if path_update_timer >= update_interval:  # 'update_interval' is a predetermined update frequency
        path_query_result = nav_server.map_create_path(nav_mesh_rid, character.get_global_transform().origin, target_position, true)
        path_update_timer = 0.0

    # Update character movement with the current path_query_result

Crowd Navigation

When dealing with multiple characters that need to navigate around each other, such as in a crowd, consider their proximity to manage potential collisions:

for character in characters:
    var path_query_result = nav_server.map_create_path(nav_mesh_rid, character.get_global_transform().origin, target_position, true)
    var path = path_query_result.get_path()

    if path.size() > 1:  # Check if there's a path available
        var next_position = path[1]  # Next position on the path
        for other_character in characters:
            if other_character != character and other_character.get_global_transform().origin.distance_to(next_position) < proximity_threshold:
                # Adjust next_position to avoid potential collision
                next_position += some_offset_vector
        # Update character movement using the adjusted next_position

With each new feature you integrate from the NavigationPathQueryResult3D class, your game becomes more enriched with complex and lifelike character movements. These code examples should empower you to handle a plethora of navigation scenarios, tuning your game’s AI to be both responsive and smart.

At Zenva, we’re passionate about providing practical knowledge that empowers our learners. By following these code examples and integrating them into your projects, you’re one step closer to creating the engaging game experiences you envision. Remember, practice is key in mastering pathfinding in Godot, and we’re thrilled to accompany you on this journey of learning and discovery.

What’s Next in Your Godot Learning Journey?

You’ve dipped your toes into the advanced world of 3D pathfinding with Godot 4, but this is just the beginning. To further sharpen your skills and continue your transformative learning journey, the Godot Game Development Mini-Degree awaits. This collection of courses is designed to guide you through the process of building cross-platform games using the latest tools and techniques available in Godot 4.

Whether you’re starting as a newbie or polishing your existing development prowess, this Mini-Degree provides a treasure trove of knowledge on game creation. You’ll tackle hands-on projects that include a variety of game genres and mechanics, all while learning at a pace that suits your lifestyle. On completing the courses, you’ll have not only a wealth of knowledge but also a professional portfolio to show off to potential employers or peers.

For those who wish to broaden their horizons even further, explore our full range of Godot tutorials through our Godot courses. Here you’ll find content that covers the essentials and beyond, helping you to go from beginner to pro. Start your adventure today with Zenva, and take the next step in forging your path as a game developer.


Embarking on the path of game development can be as thrilling as the games themselves, and with the knowledge of pathfinding in Godot 4, you’re well on your way to creating worlds that truly come to life. The power of the NavigationPathQueryResult3D class brings a new dimension of realism and interactivity to your projects, and we at Zenva are excited to see the incredible games you’ll create. Remember, every great journey begins with a single step, and each line of code is a step towards realizing your game development dreams.

Dive deeper, challenge your skills, and build your confidence with our Godot Game Development Mini-Degree. There, you will find the support and resources you need to transform your ideas into reality. Continue learning, stay curious, and create the extraordinary. We can’t wait to see what you’ll develop next. Your adventure in Godot and game creation is just beginning, and Zenva is here to guide you every step of the way.

Python Blog Image

FINAL DAYS: Unlock coding courses in Unity, Godot, Unreal, Python and more.