# BeginFindPath(NavQueryBuffer, NavLocation, NavLocation, int, NativeArray<float>)

> Initiates a pathfinding operation between two locations on the NavMesh.

## Definition

* **Type:** Method
* **Namespace:** [Unity.AI.Navigation.LowLevel](/engine/6000.5/script-reference/unity/ai/navigation/lowlevel.md)
* **Assembly:** UnityEngine.AIModule

```csharp
public readonly NavQueryStatus BeginFindPath(NavQueryBuffer queryBuffer, NavLocation start, NavLocation end, int areaMask = -1, NativeArray<float> costs = default)
```

### Parameters

**** (\[NavQueryBuffer]\(/engine/6000.5/script-reference/unity/ai/navigation/lowlevel/navquerybuffer)): The [NavQueryBuffer](/engine/6000.5/script-reference/unity/ai/navigation/lowlevel/navquerybuffer.md) used to store intermediate node data for this search operation.**** (\[NavLocation]\(/engine/6000.5/script-reference/unity/ai/navigation/lowlevel/navlocation)): The start location on the NavMesh for the path.**** (\[NavLocation]\(/engine/6000.5/script-reference/unity/ai/navigation/lowlevel/navlocation)): The location on the NavMesh where the path ends.**** (\[int]\(https\://learn.microsoft.com/dotnet/api/system.int32)): Bitmask with values of 1 at the indices of areas that can be traversed, and values of 0 for areas that aren't traversable. The default value is [NavMesh.AllAreas](/engine/6000.5/script-reference/unityengine/ai/navmesh/allareas.md).**** (\[NativeArray\<float>]\(/engine/6000.5/script-reference/unity/collections/nativearray1)): Array of custom cost values for all of the 32 possible area types. Each value must be at least `1.0f`. The default value is the set of area costs configured in the project settings.

### Returns

| Type                                                                                             | Description                                                |
| ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- |
| [NavQueryStatus](/engine/6000.5/script-reference/unity/ai/navigation/lowlevel/navquerystatus.md) | A bitfield with one of the following three main flags set: |

### Remarks

The path always begins at the specified location. If the desired end location isn't directly accessible, the search algorithm tries to find a valid location nearby.

Calling this method overrides the progress made by the specified `queryBuffer` in its previous pathfinding operation. Each [NavQueryBuffer](/engine/6000.5/script-reference/unity/ai/navigation/lowlevel/navquerybuffer.md) stores its own progress, so calling this method with a different buffer doesn't affect a search that's still in progress using another buffer.

Call [NavWorld.ContinueFindPath](/engine/6000.5/script-reference/unity/ai/navigation/lowlevel/navworld/continuefindpath.md) after this method to process the path search.

In the Editor, most invalid arguments throw an exception instead of producing a `Failure` status. This applies to a NavWorld or a [NavQueryBuffer](/engine/6000.5/script-reference/unity/ai/navigation/lowlevel/navquerybuffer.md) that isn't valid, a `start` or `end` location whose node is no longer part of the NavMesh, start and end locations that belong to NavMeshes built for different agent types, and a `costs` array that doesn't have exactly 32 elements or that contains a value below `1.0f`.

For more information about area types and the traversal costs the search applies to them, refer to Areas and Costs.

Additional Resources: [NavQueryStatus](/engine/6000.5/script-reference/unity/ai/navigation/lowlevel/navquerystatus.md), [NavMesh.GetAreaCost](/engine/6000.5/script-reference/unityengine/ai/navmesh/getareacost.md)

### Examples

```csharp
using Unity.Collections;
using UnityEngine;
using Unity.AI.Navigation.LowLevel;

public class FindPathExample : MonoBehaviour
{
    public Transform target;
    NavWorld m_World;
    NavQueryBuffer m_Buffer;

    void OnEnable()
    {
        m_World = NavWorld.GetDefaultWorld();
        m_Buffer = new NavQueryBuffer(m_World, Allocator.Persistent, 1024);
    }

    void Update()
    {
        NavLocation start = m_World.MapLocation(transform.position, Vector3.one, 0);
        NavLocation end = m_World.MapLocation(target.position, Vector3.one, 0);
        if (!m_World.IsValid(start) || !m_World.IsValid(end))
            return;

        NavQueryStatus status = m_World.BeginFindPath(m_Buffer, start, end);
        while ((status & NavQueryStatus.InProgress) != 0)
            status = m_World.ContinueFindPath(m_Buffer, 64, out int _);

        if ((status & NavQueryStatus.Success) == 0)
            return;

        status = m_World.EndFindPath(m_Buffer, out int pathSize);
        if ((status & NavQueryStatus.Success) == 0)
            return;

        NativeArray<NavNode> path = new NativeArray<NavNode>(pathSize, Allocator.Temp);
        int copied = m_World.GetResultFromFindPath(m_Buffer, path);

        // The path is a corridor of nodes, not a list of waypoints. Draw the gate that each
        // pair of consecutive nodes shares to see the corridor the agent can move through.
        for (int i = 0; i < copied - 1; i++)
        {
            if (m_World.GetPortalPoints(path[i], path[i + 1], out Vector3 left, out Vector3 right))
                Debug.DrawLine(left, right, Color.yellow);
        }

        path.Dispose();
    }

    void OnDisable()
    {
        m_Buffer.Dispose();
        m_World.Dispose();
    }
}
```

```csharp
using Unity.Collections;
using UnityEngine;
using UnityEngine.AI;
using Unity.AI.Navigation.LowLevel;

public class FindPathWithAreaCostsExample : MonoBehaviour
{
    // The navigation system defines exactly 32 area types and the costs array must match.
    const int k_AreaCount = 32;

    public Transform target;

    // Index of an area the agent should prefer to walk around, for example a "Water" area.
    public int avoidedArea = 4;
    public float avoidedAreaCost = 10f;

    NavWorld m_World;
    NavQueryBuffer m_Buffer;
    NativeArray<float> m_Costs;

    void OnEnable()
    {
        m_World = NavWorld.GetDefaultWorld();
        m_Buffer = new NavQueryBuffer(m_World, Allocator.Persistent, 1024);

        // Start from the costs configured in the Navigation settings, then override one area.
        // Every entry must be at least 1, otherwise BeginFindPath throws an ArgumentException.
        m_Costs = new NativeArray<float>(k_AreaCount, Allocator.Persistent);
        for (int i = 0; i < k_AreaCount; i++)
            m_Costs[i] = Mathf.Max(1f, NavMesh.GetAreaCost(i));

        m_Costs[avoidedArea] = Mathf.Max(1f, avoidedAreaCost);
    }

    void Update()
    {
        NavLocation start = m_World.MapLocation(transform.position, Vector3.one, 0);
        NavLocation end = m_World.MapLocation(target.position, Vector3.one, 0);
        if (!m_World.IsValid(start) || !m_World.IsValid(end))
            return;

        // Costs only bias which route the search prefers; they never make an area impassable.
        // Clear the area's bit in the areaMask when you need to block it outright.
        NavQueryStatus status = m_World.BeginFindPath(m_Buffer, start, end, NavMesh.AllAreas, m_Costs);
        while ((status & NavQueryStatus.InProgress) != 0)
            status = m_World.ContinueFindPath(m_Buffer, 64, out int _);

        if ((status & NavQueryStatus.Success) == 0)
            return;

        status = m_World.EndFindPath(m_Buffer, out int pathSize);
        if ((status & NavQueryStatus.Success) == 0)
            return;

        if ((status & NavQueryStatus.PartialResult) != 0)
            Debug.Log($"Found a partial path of {pathSize} nodes that does not reach the target.");
        else
            Debug.Log($"Found a path of {pathSize} nodes that avoids area {avoidedArea}.");
    }

    void OnDisable()
    {
        m_Costs.Dispose();
        m_Buffer.Dispose();
        m_World.Dispose();
    }
}
```
