using DotRecast.Detour;
namespace Sandbox.Navigation;
///
/// Navigation Mesh - allowing AI to navigate a world
///
public sealed partial class NavMesh
{
public Vector3? GetRandomPoint()
{
// Can be null if called before Scene.NavMesh.Init has been called
if ( query == null ) return null;
var found = query.FindRandomPoint( DtQueryNoOpFilter.Shared, Random.Shared, out var poly, out var point );
if ( found.Failed() ) return null;
return FromNav( point );
}
///
/// Get a random point on the navmesh, within the bounding box.
/// This will return null if it can't find a point on the navmesh in a few tries. Returning false doesn't mean it's impossible, our algorithm here isn't the best.
///
public Vector3? GetRandomPoint( BBox box )
{
if ( query == null ) return null;
for ( int i = 0; i < 10; i++ )
{
var pos = box.RandomPointInside;
var p = GetClosestPoint( pos );
if ( p.HasValue && box.Contains( p.Value ) )
return p.Value;
}
return null;
}
///
/// Get a random point on the navmesh, within the sphere.
/// This will return null if it can't find a point on the navmesh in a few tries. Returning false doesn't mean it's impossible, our algorithm here isn't the best.
///
public Vector3? GetRandomPoint( Vector3 position, float radius )
{
if ( query == null ) return null;
var sphere = new Sphere( position, radius );
for ( int i = 0; i < 10; i++ )
{
var pos = position + Random.Shared.VectorInSphere( radius );
var p = GetClosestPoint( pos );
if ( p.HasValue && sphere.Contains( p.Value ) )
return p.Value;
}
return default;
}
public Vector3? GetClosestPoint( BBox box )
{
if ( query == null ) return null;
var found = query.FindNearestPoly( ToNav( box.Center ), ToNav( box.Size / 2 ), DtQueryNoOpFilter.Shared, out var nearestRef, out var nearesPoint, out _ );
if ( found.Failed() || nearestRef == 0 ) return null;
return FromNav( nearesPoint );
}
public Vector3? GetClosestPoint( Vector3 position, float radius = 1024.0f ) => GetClosestPoint( BBox.FromPositionAndSize( position, radius * 2.0f ) );
public Vector3? GetClosestEdge( BBox box )
{
if ( query == null ) return null;
var foundPoly = query.FindNearestPoly( ToNav( box.Center ), ToNav( box.Size / 2 ), DtQueryNoOpFilter.Shared, out var nearestPoly, out var nearesPoint, out _ );
if ( foundPoly.Failed() || nearestPoly == 0 ) return null;
var found = query.FindDistanceToWall( nearestPoly, ToNav( box.Center ), box.Size.Length, DtQueryNoOpFilter.Shared, out var _, out var hitPos, out var _ );
if ( found.Failed() ) return null;
return FromNav( hitPos );
}
public Vector3? GetClosestEdge( Vector3 position, float radius = 1024.0f ) => GetClosestEdge( BBox.FromPositionAndSize( position, radius * 2.0f ) );
}