generated from amasson/UnrealEngineProject
auto run
This commit is contained in:
106
Source/Wailing/Private/Components/AutoRunComponent.cpp
Normal file
106
Source/Wailing/Private/Components/AutoRunComponent.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// 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;
|
||||
}
|
||||
@@ -2,4 +2,102 @@
|
||||
|
||||
|
||||
#include "Player/WLPlayerController.h"
|
||||
#include "Components/InteractionControllerComponent.h"
|
||||
#include "Components/AutoRunComponent.h"
|
||||
#include "EnhancedInputSubsystems.h"
|
||||
#include "EnhancedInputComponent.h"
|
||||
|
||||
|
||||
AWLPlayerController::AWLPlayerController()
|
||||
{
|
||||
InteractionComponent = CreateDefaultSubobject<UInteractionControllerComponent>("InteractionComponent");
|
||||
AutoRunComponent = CreateDefaultSubobject<UAutoRunComponent>("AutoRunComponent");
|
||||
|
||||
bShowMouseCursor = true;
|
||||
DefaultMouseCursor = EMouseCursor::Default;
|
||||
}
|
||||
|
||||
void AWLPlayerController::BeginPlay()
|
||||
{
|
||||
Super::BeginPlay();
|
||||
|
||||
if (UEnhancedInputLocalPlayerSubsystem* InputSubsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer()))
|
||||
{
|
||||
checkf(InputContext, TEXT("WLPlayerController: Invalid Input Context"));
|
||||
InputSubsystem->AddMappingContext(InputContext, 0);
|
||||
}
|
||||
|
||||
FInputModeGameAndUI InputModeData;
|
||||
InputModeData.SetLockMouseToViewportBehavior(EMouseLockMode::DoNotLock);
|
||||
InputModeData.SetHideCursorDuringCapture(false);
|
||||
SetInputMode(InputModeData);
|
||||
}
|
||||
|
||||
void AWLPlayerController::AcknowledgePossession(APawn* P)
|
||||
{
|
||||
Super::AcknowledgePossession(P);
|
||||
|
||||
AutoRunComponent->SetControlledPawn(P);
|
||||
}
|
||||
|
||||
void AWLPlayerController::SetupInputComponent()
|
||||
{
|
||||
Super::SetupInputComponent();
|
||||
|
||||
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(InputComponent))
|
||||
{
|
||||
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &ThisClass::Move);
|
||||
EnhancedInputComponent->BindAction(HoldPositionAction, ETriggerEvent::Triggered, this, &ThisClass::HoldPositionPressed);
|
||||
EnhancedInputComponent->BindAction(HoldPositionAction, ETriggerEvent::Completed, this, &ThisClass::HoldPositionReleased);
|
||||
EnhancedInputComponent->BindAction(AutoRunAction, ETriggerEvent::Started, this, &ThisClass::AutoRunPressed);
|
||||
EnhancedInputComponent->BindAction(AutoRunAction, ETriggerEvent::Triggered, this, &ThisClass::AutoRunHeld);
|
||||
EnhancedInputComponent->BindAction(AutoRunAction, ETriggerEvent::Completed, this, &ThisClass::AutoRunReleased);
|
||||
}
|
||||
}
|
||||
|
||||
void AWLPlayerController::Move(const FInputActionValue& InputActionValue)
|
||||
{
|
||||
const FVector2D InputAxisVector = InputActionValue.Get<FVector2D>();
|
||||
|
||||
if (InputAxisVector.IsNearlyZero())
|
||||
return;
|
||||
|
||||
AutoRunComponent->StopAutoRun();
|
||||
const FRotator Rotation = GetControlRotation();
|
||||
const FRotator YawRotation(0.0f, Rotation.Yaw, 0.0f);
|
||||
const FRotationMatrix RotationMatrix(YawRotation);
|
||||
|
||||
const FVector ForwardVector = RotationMatrix.GetUnitAxis(EAxis::X);
|
||||
const FVector RightVector = RotationMatrix.GetUnitAxis(EAxis::Y);
|
||||
|
||||
if (APawn* ControlledPawn = GetPawn<APawn>())
|
||||
{
|
||||
ControlledPawn->AddMovementInput(ForwardVector, InputAxisVector.Y);
|
||||
ControlledPawn->AddMovementInput(RightVector, InputAxisVector.X);
|
||||
}
|
||||
}
|
||||
|
||||
void AWLPlayerController::AutoRunPressed()
|
||||
{
|
||||
AutoRunComponent->AutoRunKeyPressed();
|
||||
}
|
||||
|
||||
void AWLPlayerController::AutoRunHeld()
|
||||
{
|
||||
AutoRunComponent->AutoRunKeyHold(GetWorld()->GetDeltaSeconds(), InteractionComponent->GetCursorHit());
|
||||
}
|
||||
|
||||
void AWLPlayerController::AutoRunReleased()
|
||||
{
|
||||
AutoRunComponent->AutoRunKeyReleased();
|
||||
}
|
||||
|
||||
void AWLPlayerController::HoldPositionPressed()
|
||||
{
|
||||
AutoRunComponent->HoldPositionPressed();
|
||||
}
|
||||
|
||||
void AWLPlayerController::HoldPositionReleased()
|
||||
{
|
||||
AutoRunComponent->HoldPositionReleased();
|
||||
}
|
||||
|
||||
73
Source/Wailing/Public/Components/AutoRunComponent.h
Normal file
73
Source/Wailing/Public/Components/AutoRunComponent.h
Normal file
@@ -0,0 +1,73 @@
|
||||
// Amasson
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "Components/ActorComponent.h"
|
||||
#include "AutoRunComponent.generated.h"
|
||||
|
||||
class USplineComponent;
|
||||
|
||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnAutoWalkBeginSignature, UAutoRunComponent*, AutoRunComponent, FVector, Destination);
|
||||
|
||||
|
||||
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
|
||||
class WAILING_API UAutoRunComponent : public UActorComponent
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
public:
|
||||
|
||||
UAutoRunComponent();
|
||||
|
||||
UPROPERTY(BlueprintAssignable)
|
||||
FOnAutoWalkBeginSignature OnAutoWalkBegin;
|
||||
|
||||
void SetControlledPawn(APawn* Pawn);
|
||||
|
||||
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
|
||||
|
||||
void StopAutoRun();
|
||||
|
||||
void AutoRunKeyPressed();
|
||||
void AutoRunKeyReleased();
|
||||
void AutoRunKeyHold(float DeltaTime, const FHitResult& CursorHit);
|
||||
|
||||
void HoldPositionPressed()
|
||||
{
|
||||
bIsHoldingPosition = true;
|
||||
}
|
||||
|
||||
void HoldPositionReleased()
|
||||
{
|
||||
bIsHoldingPosition = false;
|
||||
}
|
||||
|
||||
bool ShouldAutoRun()
|
||||
{
|
||||
return !bIsHoldingPosition;
|
||||
}
|
||||
|
||||
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Components")
|
||||
USplineComponent* GetPathSpline() const { return PathSpline; }
|
||||
|
||||
private:
|
||||
|
||||
FVector CachedDestination = FVector::ZeroVector;
|
||||
float FollowTime = 0.0f;
|
||||
float ShortPressThreshold = 0.2f;
|
||||
bool bAutoRunning = false;
|
||||
|
||||
UPROPERTY(EditDefaultsOnly)
|
||||
float AutoRunAcceptanceRadius = 50.0f;
|
||||
|
||||
UPROPERTY(VisibleAnywhere)
|
||||
TObjectPtr<USplineComponent> PathSpline;
|
||||
|
||||
TObjectPtr<APawn> ControlledPawn;
|
||||
|
||||
bool bIsHoldingPosition;
|
||||
|
||||
bool IsAtDestination() const;
|
||||
|
||||
};
|
||||
@@ -6,6 +6,8 @@
|
||||
#include "Player/GRPlayerController.h"
|
||||
#include "WLPlayerController.generated.h"
|
||||
|
||||
class UInputAction;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@@ -14,4 +16,45 @@ class WAILING_API AWLPlayerController : public AGRPlayerController
|
||||
{
|
||||
GENERATED_BODY()
|
||||
|
||||
protected:
|
||||
|
||||
AWLPlayerController();
|
||||
|
||||
virtual void BeginPlay() override;
|
||||
|
||||
virtual void AcknowledgePossession(APawn* P) override;
|
||||
|
||||
virtual void SetupInputComponent() override;
|
||||
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Components", meta = (AllowPrivateAccess = true))
|
||||
TObjectPtr<class UInteractionControllerComponent> InteractionComponent;
|
||||
|
||||
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "AutoRun", meta = (AllowPrivateAccess = true))
|
||||
TObjectPtr<class UAutoRunComponent> AutoRunComponent;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "Input")
|
||||
TObjectPtr<class UInputMappingContext> InputContext;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "Input")
|
||||
TObjectPtr<UInputAction> MoveAction;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "Input")
|
||||
TObjectPtr<UInputAction> HoldPositionAction;
|
||||
|
||||
UPROPERTY(EditAnywhere, Category = "Input")
|
||||
TObjectPtr<UInputAction> AutoRunAction;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
void Move(const struct FInputActionValue& InputActionValue);
|
||||
|
||||
void AutoRunPressed();
|
||||
void AutoRunHeld();
|
||||
void AutoRunReleased();
|
||||
|
||||
void HoldPositionPressed();
|
||||
void HoldPositionReleased();
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user