menu_bookDocumentation

NavMeshAgent: MoveTo, WishVelocity Pattern, Off-Mesh Links, Area Constraints, and Path Queries

calendar_today May 4, 2026 schedule ~1 min read person patrickjr verified 50
NavMeshAgent is the s&box component for AI navigation using the scene's navmesh. It uses DotRecast (Detour/Crowd) internally and integrates with the NavMeshAgentSystem for crowd simulation.

Basic Usage

CSHARP
var agent = GetComponent<NavMeshAgent>();

// Navigate to a position
agent.MoveTo( targetPosition );

// Stop navigation
agent.Stop();

// Check if navigating
if ( agent.IsNavigating )
{
    // Use WishVelocity to drive a PlayerController
    controller.WishVelocity = agent.WishVelocity;
}

WishVelocity Pattern

The most common pattern is to use WishVelocity to drive a PlayerController. WishVelocity is the crowd-computed desired velocity — it already accounts for obstacle avoidance and separation from other agents.

CSHARP
protected override void OnFixedUpdate()
{
    if ( IsProxy ) return;

    agent.MoveTo( targetPosition );

    if ( agent.IsNavigating )
    {
        controller.WishVelocity = agent.WishVelocity;
    }
    else
    {
        controller.WishVelocity = Vector3.Zero;
    }
}

Key Properties

CSHARP
agent.Height = 64f;          // agent capsule height
agent.Radius = 16f;          // agent capsule radius
agent.MaxSpeed = 120f;       // maximum movement speed
agent.Acceleration = 120f;   // how fast velocity changes (snappy = high value)
agent.Separation = 0.25f;    // crowd separation strength [0..1]
agent.UpdatePosition = true; // auto-update GameObject position
agent.UpdateRotation = false; // auto-rotate toward movement direction
agent.AutoTraverseLinks = true; // auto-traverse off-mesh links

agent.AgentPosition    // current agent position (even if UpdatePosition = false)
agent.TargetPosition   // current target position (null if not navigating)
agent.Velocity         // current velocity
agent.WishVelocity     // desired velocity (use this to drive movement)

When AutoTraverseLinks = false, you handle link traversal yourself (e.g., for jumping or climbing):

CSHARP
agent.AutoTraverseLinks = false;
agent.LinkEnter = () =>
{
    var data = agent.CurrentLinkTraversal.Value;
    // data.LinkEnterPosition, data.LinkExitPosition, data.LinkComponent
    StartJump( data.LinkEnterPosition, data.LinkExitPosition );
};
agent.LinkExit = () => { /* link traversal complete */ };

// When done traversing:
agent.CompleteLinkTraversal();

Area Constraints

CSHARP
// Only allow specific areas
agent.AllowedAreas.Add( myNavMeshArea );

// Forbid specific areas
agent.ForbiddenAreas.Add( dangerArea );

// Allow/disallow the default area
agent.AllowDefaultArea = true;

Path Queries

CSHARP
// Get current path (not free — avoid calling every frame)
var path = agent.GetPath();
if ( path.Status == NavMeshPathStatus.Complete )
{
    foreach ( var point in path.Points )
        Log.Info( point.Position );
}

// Look-ahead position (for rotation)
var lookTarget = agent.GetLookAhead( 30f );
Was this helpful?