2023-12-12 15:42:16 -05:00
// Copyright Epic Games, Inc. All Rights Reserved.
# include "SplineNavModifierComponent.h"
# include "AI/NavigationSystemBase.h"
2024-01-17 20:34:52 -05:00
# include "AI/Navigation/NavigationRelevantData.h"
2023-12-12 15:42:16 -05:00
# include "Components/SplineComponent.h"
# include "VisualLogger/VisualLogger.h"
# include UE_INLINE_GENERATED_CPP_BY_NAME(SplineNavModifierComponent)
namespace
{
const USplineComponent * GetSpline ( const AActor * Owner )
{
if ( ! Owner )
{
UE_LOG ( LogNavigation , Warning , TEXT ( " USplineNavModifierComponent has no owner, cannot proceed " ) ) ;
return nullptr ;
}
const USplineComponent * Spline = Owner - > GetComponentByClass < USplineComponent > ( ) ;
2023-12-13 09:59:54 -05:00
UE_CVLOG_UELOG ( ! Spline , Owner , LogNavigation , Warning , TEXT ( " USplineNavModifierComponent attached to \" %s \" could not find a spline component, cannot proceed " ) , * Owner - > GetName ( ) ) ;
2023-12-12 15:42:16 -05:00
return Spline ;
}
}
void USplineNavModifierComponent : : CalculateBounds ( ) const
{
if ( const USplineComponent * Spline = GetSpline ( GetOwner ( ) ) )
{
2023-12-13 09:59:54 -05:00
Bounds = Spline - > CalcBounds ( GetOwner ( ) - > GetTransform ( ) ) . GetBox ( ) ;
2023-12-12 15:42:16 -05:00
}
}
void USplineNavModifierComponent : : GetNavigationData ( FNavigationRelevantData & Data ) const
{
const USplineComponent * Spline = GetSpline ( GetOwner ( ) ) ;
if ( ! Spline )
{
return ;
}
// Square in the YZ plane used to sample the spline at each cross section
constexpr int32 SampleVertices = 4 ;
TStaticArray < FVector , SampleVertices > SampleSquare ;
SampleSquare [ 0 ] = FVector ( 0 , - SplineExtent , - SplineExtent ) ;
SampleSquare [ 1 ] = FVector ( 0 , SplineExtent , - SplineExtent ) ;
SampleSquare [ 2 ] = FVector ( 0 , SplineExtent , SplineExtent ) ;
SampleSquare [ 3 ] = FVector ( 0 , - SplineExtent , SplineExtent ) ;
// Vertices (in no particular order) of a prism which will enclose each segment of the spline
// @Note The only reason Tube isn't a TStaticArray is because FAreaNavModifier expects a TArray
TArray < FVector > Tube ;
Tube . SetNum ( SampleSquare . Num ( ) * 2 ) ;
// Always sample at least the start and end points
const int32 NumPoints = FMath : : Max ( NumSplineSamples , 2 ) ;
const float SplineLength = Spline - > GetSplineLength ( ) ;
FTransform PreviousTransform ;
for ( int32 SampleIndex = 0 ; SampleIndex < NumPoints ; SampleIndex + + )
{
// Sample a point on the spline at the current distance
const double Distance = SplineLength * SampleIndex / ( NumPoints - 1 ) ;
const FTransform CurrentTransform = Spline - > GetTransformAtDistanceAlongSpline ( Distance , ESplineCoordinateSpace : : World ) ;
if ( SampleIndex > 0 )
{
// Compute the vertices of the current tube segment
for ( int i = 0 ; i < SampleVertices ; i + + )
{
Tube [ i ] = PreviousTransform . TransformPosition ( SampleSquare [ i ] ) ;
Tube [ i + SampleVertices ] = CurrentTransform . TransformPosition ( SampleSquare [ i ] ) ;
}
// From the tube construct a convex hull whose volume will be used to mark the nav mesh with the selected AreaClass
const FAreaNavModifier NavModifier ( Tube , ENavigationCoordSystem : : Type : : Unreal , FTransform : : Identity , AreaClass ) ;
Data . Modifiers . Add ( NavModifier ) ;
}
PreviousTransform = CurrentTransform ;
}
}