Version: Unity 6.5 (6000.5)
LanguageEnglish
  • C#

NavWorld.BeginFindPath

Suggest a change

Success!

Thank you for helping us improve the quality of Unity Documentation. Although we cannot accept all submissions, we do read each suggested change from our users and will make updates where applicable.

Close

Submission failed

For some reason your suggested change could not be submitted. Please <a>try again</a> in a few minutes. And thank you for taking the time to help us improve the quality of Unity Documentation.

Close

Cancel

Declaration

public NavQueryStatus BeginFindPath(NavQueryBuffer queryBuffer, NavLocation start, NavLocation end, int areaMask, NativeArray<float> costs);

Parameters

Parameter Description
queryBuffer The NavQueryBuffer used to store intermediate node data for this search operation.
start The start location on the NavMesh for the path.
end The location on the NavMesh where the path ends.
areaMask 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.
costs 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

NavQueryStatus A bitfield with one of the following three main flags set:

InProgress if the operation is successful and the query is ready to search for a path.

Failure, combined with NavQueryStatus.InvalidParameter, if the queryBuffer isn't created for this NavWorld or is no longer valid. Outside the Editor this status also covers the other invalid arguments that the Editor reports by throwing an exception.

Success if the pathfinding operation starts and ends in the same NavNode.

Description

Initiates a pathfinding operation between two locations on the NavMesh.

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 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 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 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, NavMesh.GetAreaCost

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();
    }
}
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();
    }
}