terminalCode Example

NavMesh Links: Custom Jump and Ladder Traversal for AI Agents

calendar_today May 20, 2026 schedule ~1 min read person PatrickJr verified 50

NavMesh Links connect disconnected NavMesh regions (jumps, ladders, teleports). By default agents linearly interpolate between endpoints, but you can implement custom traversal for realistic movement.

Add a NavMeshLink component to a GameObject. Edit start/end positions via inspector or editor tools.

Custom Traversal: Parabolic Jump

Disable auto-traversal and drive movement manually:

CSHARP
public sealed class JumpLink : NavMeshLink
{
    protected override void OnLinkEntered( NavMeshAgent agent )
    {
        ParabolicJump( agent );
    }

    private async void ParabolicJump( NavMeshAgent agent )
    {
        var start = agent.CurrentLinkTraversal.Value.AgentInitialPosition;
        var end = agent.CurrentLinkTraversal.Value.LinkExitPosition;

        var heightDifference = end.z - start.z;
        var peakHeight = MathF.Abs( heightDifference ) + 25f;
        var mid = (start + end) / 2f;

        var startToMid = mid.WithZ( peakHeight ) - start;
        var midToEnd = end - mid.WithZ( peakHeight );
        var duration = MathF.Max( 0.75f, (startToMid + midToEnd).Length / agent.MaxSpeed );

        TimeSince timeSinceStart = 0;

        while ( timeSinceStart < duration )
        {
            var t = timeSinceStart / duration;
            var newPosition = Vector3.Lerp( start, end, t );
            var yOffset = 4f * peakHeight * t * (1f - t);
            newPosition.z = MathX.Lerp( start.z, end.z, t ) + yOffset;

            agent.SetAgentPosition( newPosition );
            await Task.Frame();
        }

        agent.SetAgentPosition( end );
        agent.CompleteLinkTraversal();
    }
}

Custom Traversal: Ladder Climb

Three-phase movement: align → climb vertically → walk off:

CSHARP
public sealed class LadderLink : NavMeshLink
{
    protected override void OnLinkEntered( NavMeshAgent agent )
    {
        ClimbLadder( agent );
    }

    private async void ClimbLadder( NavMeshAgent agent )
    {
        var initialPos = agent.CurrentLinkTraversal.Value.AgentInitialPosition;
        var start = agent.CurrentLinkTraversal.Value.LinkEnterPosition;
        var endVertical = start.WithZ( agent.CurrentLinkTraversal.Value.LinkExitPosition.z );
        var end = agent.CurrentLinkTraversal.Value.LinkExitPosition;

        var climbSpeed = 100f;
        var startDuration = (start - initialPos).Length / climbSpeed;
        var climbDuration = (endVertical - start).Length / climbSpeed;
        var endDuration = (end - endVertical).Length / climbSpeed;
        var totalTime = startDuration + climbDuration + endDuration;

        TimeSince timeSinceStart = 0;

        while ( timeSinceStart < totalTime )
        {
            Vector3 pos;
            if ( timeSinceStart < startDuration )
                pos = Vector3.Lerp( initialPos, start, timeSinceStart / startDuration );
            else if ( timeSinceStart < startDuration + climbDuration )
                pos = Vector3.Lerp( start, endVertical, (timeSinceStart - startDuration) / climbDuration );
            else
                pos = Vector3.Lerp( endVertical, end, (timeSinceStart - startDuration - climbDuration) / endDuration );

            agent.SetAgentPosition( pos );
            await Task.Frame();
        }

        agent.SetAgentPosition( end );
        agent.CompleteLinkTraversal();
    }
}

Key API

Was this helpful?