295 lines
8.4 KiB
C
295 lines
8.4 KiB
C
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
#pragma once
|
|
|
|
#include "MassEntityTypes.h"
|
|
#include "ZoneGraphTypes.h"
|
|
#include "MassCommonTypes.h"
|
|
#include "MassZoneGraphNavigationTypes.h"
|
|
#include "Containers/StaticArray.h"
|
|
#include "MassZoneGraphNavigationFragments.generated.h"
|
|
|
|
#define UE_API MASSZONEGRAPHNAVIGATION_API
|
|
|
|
|
|
USTRUCT()
|
|
struct FMassZoneGraphNavigationParameters : public FMassConstSharedFragment
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
/** Filter describing which lanes can be used when spawned. */
|
|
UPROPERTY(EditAnywhere, Category="Navigation")
|
|
FZoneGraphTagFilter LaneFilter;
|
|
|
|
/** Query radius when trying to find nearest lane when spawned. */
|
|
UPROPERTY(EditAnywhere, Category="Navigation", meta = (UIMin = 0.0, ClampMin = 0.0, ForceUnits="cm"))
|
|
float QueryRadius = 500.0f;
|
|
};
|
|
|
|
|
|
/** Stores path request associated to a new movement action. This is used to replicate actions. */
|
|
USTRUCT()
|
|
struct FMassZoneGraphPathRequestFragment : public FMassFragment
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
/** Short path request Handle to current lane. */
|
|
UPROPERTY(Transient)
|
|
FZoneGraphShortPathRequest PathRequest;
|
|
};
|
|
|
|
/** Describes current location on ZoneGraph */
|
|
USTRUCT()
|
|
struct FMassZoneGraphLaneLocationFragment : public FMassFragment
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
/** Handle to current lane. */
|
|
FZoneGraphLaneHandle LaneHandle;
|
|
|
|
/** Distance along current lane. */
|
|
float DistanceAlongLane = 0.0f;
|
|
|
|
/** Cached lane length, used for clamping and testing if at end of lane. */
|
|
float LaneLength = 0.0f;
|
|
};
|
|
|
|
/** Describes part of a ZoneGraph lane. */
|
|
USTRUCT()
|
|
struct FMassZoneGraphCachedLaneFragment : public FMassFragment
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
static constexpr uint8 MaxPoints = 5;
|
|
|
|
void Reset()
|
|
{
|
|
LaneHandle.Reset();
|
|
LaneLength = 0.0f;
|
|
LaneWidth = FMassInt16Real(0.0f);
|
|
NumPoints = 0;
|
|
}
|
|
|
|
/** Caches portion of a lane from ZoneGraph. */
|
|
UE_API void CacheLaneData(const FZoneGraphStorage& ZoneGraphStorage, const FZoneGraphLaneHandle CurrentLaneHandle,
|
|
const float CurrentDistanceAlongLane, const float TargetDistanceAlongLane, const float InflateDistance);
|
|
|
|
int32 FindSegmentIndexAtDistance(const float DistanceAlongPath) const
|
|
{
|
|
int32 SegmentIndex = 0;
|
|
while (SegmentIndex < ((int32)NumPoints - 2))
|
|
{
|
|
if (DistanceAlongPath < LanePointProgressions[SegmentIndex + 1].Get())
|
|
{
|
|
break;
|
|
}
|
|
SegmentIndex++;
|
|
}
|
|
|
|
return SegmentIndex;
|
|
}
|
|
|
|
float GetInterpolationTimeOnSegment(const int32 SegmentIndex, const float DistanceAlongPath) const
|
|
{
|
|
check(SegmentIndex >= 0 && SegmentIndex <= (int32)NumPoints - 2);
|
|
const float StartDistance = LanePointProgressions[SegmentIndex].Get();
|
|
const float EndDistance = LanePointProgressions[SegmentIndex + 1].Get();
|
|
const float SegLength = EndDistance - StartDistance;
|
|
const float InvSegLength = SegLength > KINDA_SMALL_NUMBER ? 1.0f / SegLength : 0.0f;
|
|
return FMath::Clamp((DistanceAlongPath - StartDistance) * InvSegLength, 0.0f, 1.0f);
|
|
}
|
|
|
|
void InterpolatePointAndTangentOnSegment(const int32 SegmentIndex, const float DistanceAlongPath, FVector& OutPoint, FVector& OutTangent) const
|
|
{
|
|
const float T = GetInterpolationTimeOnSegment(SegmentIndex, DistanceAlongPath);
|
|
OutPoint = FMath::Lerp(LanePoints[SegmentIndex], LanePoints[SegmentIndex + 1], T);
|
|
OutTangent = FVector(FMath::Lerp(LaneTangentVectors[SegmentIndex].Get(), LaneTangentVectors[SegmentIndex + 1].Get(), T), 0.0f);
|
|
}
|
|
|
|
FVector InterpolatePointOnSegment(const int32 SegmentIndex, const float DistanceAlongPath) const
|
|
{
|
|
const float T = GetInterpolationTimeOnSegment(SegmentIndex, DistanceAlongPath);
|
|
return FMath::Lerp(LanePoints[SegmentIndex], LanePoints[SegmentIndex + 1], T);
|
|
}
|
|
|
|
void GetPointAndTangentAtDistance(const float DistanceAlongPath, FVector& OutPoint, FVector& OutTangent) const
|
|
{
|
|
if (NumPoints == 0)
|
|
{
|
|
OutPoint = FVector::ZeroVector;
|
|
OutTangent = FVector::ForwardVector;
|
|
return;
|
|
}
|
|
if (NumPoints == 1)
|
|
{
|
|
OutPoint = LanePoints[0];
|
|
OutTangent = FVector(LaneTangentVectors[0].Get(), 0.0f);
|
|
return;
|
|
}
|
|
|
|
const int32 SegmentIndex = FindSegmentIndexAtDistance(DistanceAlongPath);
|
|
InterpolatePointAndTangentOnSegment(SegmentIndex, DistanceAlongPath, OutPoint, OutTangent);
|
|
}
|
|
|
|
FVector GetPointAtDistance(const float DistanceAlongPath) const
|
|
{
|
|
if (NumPoints == 0)
|
|
{
|
|
return FVector::ZeroVector;
|
|
}
|
|
if (NumPoints == 1)
|
|
{
|
|
return LanePoints[0];
|
|
}
|
|
|
|
const int32 SegmentIndex = FindSegmentIndexAtDistance(DistanceAlongPath);
|
|
return InterpolatePointOnSegment(SegmentIndex, DistanceAlongPath);
|
|
}
|
|
|
|
bool IsDistanceAtLaneExtrema(const float Distance) const
|
|
{
|
|
static constexpr float Epsilon = 0.1f;
|
|
return Distance <= Epsilon || (Distance - LaneLength) >= -Epsilon;
|
|
}
|
|
|
|
FZoneGraphLaneHandle LaneHandle;
|
|
|
|
/** Lane points */
|
|
TStaticArray<FVector, MaxPoints> LanePoints;
|
|
|
|
/** Cached length of the lane. */
|
|
float LaneLength = 0.0f;
|
|
|
|
/** Lane tangents */
|
|
TStaticArray<FMassSnorm8Vector2D, MaxPoints> LaneTangentVectors;
|
|
|
|
/** lane Advance distances */
|
|
TStaticArray<FMassInt16Real10, MaxPoints> LanePointProgressions;
|
|
|
|
/** Cached width of the lane. */
|
|
FMassInt16Real LaneWidth = FMassInt16Real(0.0f);
|
|
|
|
/** Additional space left of the lane */
|
|
FMassInt16Real LaneLeftSpace = FMassInt16Real(0.0f);
|
|
|
|
/** Additional space right of the lane */
|
|
FMassInt16Real LaneRightSpace = FMassInt16Real(0.0f);
|
|
|
|
/** ID incremented each time the cache is updated. */
|
|
uint16 CacheID = 0;
|
|
|
|
/** Number of points on path. */
|
|
uint8 NumPoints = 0;
|
|
};
|
|
|
|
USTRUCT()
|
|
struct FMassZoneGraphPathPoint
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
/** Position of the path. */
|
|
FVector Position = FVector::ZeroVector;
|
|
|
|
/** Tangent direction of the path. */
|
|
FMassSnorm8Vector2D Tangent;
|
|
|
|
/** Position of the point along the original path. (Could potentially be uint16 at 10cm accuracy) */
|
|
FMassInt16Real10 DistanceAlongLane = FMassInt16Real10(0.0f);
|
|
|
|
/** Distance along the offset path from first point. (Could potentially be uint16 at 10cm accuracy) */
|
|
FMassInt16Real Distance = FMassInt16Real(0.0f);
|
|
|
|
/** True if this point is assumed to be off lane. */
|
|
uint8 bOffLane : 1;
|
|
|
|
/** True if this point is lane start or end point. */
|
|
uint8 bIsLaneExtrema : 1;
|
|
};
|
|
|
|
/** Describes short path along ZoneGraph */
|
|
// @todo MassMovement: it should be possible to prune this down to 64bytes
|
|
// - remove debug lane handle, and replace other with index
|
|
// - see if we can remove move tangent?
|
|
USTRUCT()
|
|
struct FMassZoneGraphShortPathFragment : public FMassFragment
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
FMassZoneGraphShortPathFragment() = default;
|
|
|
|
static constexpr uint8 MaxPoints = 3;
|
|
|
|
void Reset()
|
|
{
|
|
#if WITH_MASSGAMEPLAY_DEBUG
|
|
DebugLaneHandle.Reset();
|
|
#endif
|
|
NextLaneHandle.Reset();
|
|
NextExitLinkType = EZoneLaneLinkType::None;
|
|
ProgressDistance = 0.0f;
|
|
NumPoints = 0;
|
|
bMoveReverse = false;
|
|
EndOfPathIntent = EMassMovementAction::Stand;
|
|
bPartialResult = false;
|
|
bDone = false;
|
|
}
|
|
|
|
/** Requests path along the current lane */
|
|
UE_API bool RequestPath(const FMassZoneGraphCachedLaneFragment& CachedLane, const FZoneGraphShortPathRequest& Request, const float CurrentDistanceAlongLane, const float AgentRadius);
|
|
|
|
/** Requests path to stand at current position. */
|
|
UE_API bool RequestStand(const FMassZoneGraphCachedLaneFragment& CachedLane, const float CurrentDistanceAlongLane, const FVector& CurrentPosition);
|
|
|
|
bool IsDone() const
|
|
{
|
|
// @todo MassMovement: should we remove NumPoints == 0? The logic used to be quite different when it was really needed.
|
|
return NumPoints == 0 || bDone;
|
|
}
|
|
|
|
#if WITH_MASSGAMEPLAY_DEBUG
|
|
/** Current lane handle, for debug */
|
|
FZoneGraphLaneHandle DebugLaneHandle;
|
|
#endif
|
|
|
|
/** If valid, the this lane will be set as current lane after the path follow is completed. */
|
|
FZoneGraphLaneHandle NextLaneHandle;
|
|
|
|
/** Current progress distance along the lane. */
|
|
float ProgressDistance = 0.0f;
|
|
|
|
/** Path points */
|
|
TStaticArray<FMassZoneGraphPathPoint, MaxPoints> Points;
|
|
|
|
/** If next lane is set, this is how to reach the lane from current lane. */
|
|
EZoneLaneLinkType NextExitLinkType = EZoneLaneLinkType::None;
|
|
|
|
/** Number of points on path. */
|
|
uint8 NumPoints = 0;
|
|
|
|
/** Intent at the end of the path. */
|
|
EMassMovementAction EndOfPathIntent = EMassMovementAction::Stand;
|
|
|
|
/** True if we're moving reverse */
|
|
uint8 bMoveReverse : 1;
|
|
|
|
/** True if the path was partial. */
|
|
uint8 bPartialResult : 1;
|
|
|
|
/** True when path follow is completed. */
|
|
uint8 bDone : 1;
|
|
};
|
|
|
|
USTRUCT()
|
|
struct FMassLaneCacheBoundaryFragment : public FMassFragment
|
|
{
|
|
GENERATED_BODY()
|
|
|
|
/** Last update position. */
|
|
FVector LastUpdatePosition = FVector::ZeroVector;
|
|
|
|
/** Lane cached ID at last update. */
|
|
uint16 LastUpdateCacheID = 0;
|
|
};
|
|
|
|
#undef UE_API
|