Files
Wailing/Source/Wailing/Private/Components/AutoRunComponent.cpp
2025-12-25 01:20:33 +01:00

107 lines
3.1 KiB
C++

// Amasson
#include "Components/AutoRunComponent.h"
#include "Components/SplineComponent.h"
#include "NavigationSystem.h"
#include "NavigationPath.h"
UAutoRunComponent::UAutoRunComponent()
{
PrimaryComponentTick.bCanEverTick = true;
PathSpline = CreateDefaultSubobject<USplineComponent>("PathSpline");
}
void UAutoRunComponent::SetControlledPawn(APawn* Pawn)
{
ControlledPawn = Pawn;
}
void UAutoRunComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (bAutoRunning)
if (IsValid(ControlledPawn) && IsValid(PathSpline))
{
const FVector PawnLocation = ControlledPawn->GetActorLocation();
const float ClosePointKey = PathSpline->FindInputKeyClosestToWorldLocation(PawnLocation);
const FVector LocationOnSpline = PathSpline->GetLocationAtSplineInputKey(ClosePointKey, ESplineCoordinateSpace::World);
const FVector SplineDirection = PathSpline->GetDirectionAtSplineInputKey(ClosePointKey, ESplineCoordinateSpace::World);
const FVector NextTargetPoint = PathSpline->GetLocationAtSplineInputKey(FMath::CeilToFloat(ClosePointKey + 0.5), ESplineCoordinateSpace::World);
FVector DirectionToNextTargetPoint = NextTargetPoint - PawnLocation;
DirectionToNextTargetPoint.Normalize();
ControlledPawn->AddMovementInput((SplineDirection + DirectionToNextTargetPoint) / 2);
if (ClosePointKey >= static_cast<float>(PathSpline->GetNumberOfSplinePoints()) - 1.1)
bAutoRunning = false;
}
}
void UAutoRunComponent::StopAutoRun()
{
bAutoRunning = false;
}
void UAutoRunComponent::AutoRunKeyPressed()
{
FollowTime = 0;
bAutoRunning = false;
}
void UAutoRunComponent::AutoRunKeyReleased()
{
if (!IsValid(ControlledPawn))
return;
if (FollowTime < ShortPressThreshold)
{
if (UNavigationPath* NavPath = UNavigationSystemV1::FindPathToLocationSynchronously(this, ControlledPawn->GetActorLocation(), CachedDestination))
{
if (IsValid(PathSpline))
{
PathSpline->ClearSplinePoints();
for (const FVector& PointLoc : NavPath->PathPoints)
{
PathSpline->AddSplinePoint(PointLoc, ESplineCoordinateSpace::World);
}
}
if (!NavPath->PathPoints.IsEmpty())
CachedDestination = NavPath->PathPoints[NavPath->PathPoints.Num() - 1];
OnAutoWalkBegin.Broadcast(this, CachedDestination);
bAutoRunning = true;
}
}
}
void UAutoRunComponent::AutoRunKeyHold(float DeltaTime, const FHitResult& CursorHit)
{
FollowTime += DeltaTime;
if (CursorHit.bBlockingHit)
{
CachedDestination = CursorHit.ImpactPoint;
if (IsValid(ControlledPawn))
{
const FVector WorldDirection = (CachedDestination - ControlledPawn->GetActorLocation()).GetSafeNormal();
ControlledPawn->AddMovementInput(WorldDirection);
}
}
}
bool UAutoRunComponent::IsAtDestination() const
{
if (!IsValid(ControlledPawn))
return false;
const float SquaredDistanceToDestination = (ControlledPawn->GetActorLocation() - CachedDestination).SquaredLength();
const float SquaredAcceptanceRadius = AutoRunAcceptanceRadius * AutoRunAcceptanceRadius;
return SquaredDistanceToDestination <= SquaredAcceptanceRadius;
}