Add Flatten Spline into Combat Platformer Path

This commit is contained in:
Maxime Maurin 2023-11-23 00:06:48 +01:00
parent 29fd695a03
commit 028e228c8f
16 changed files with 61 additions and 56 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,7 @@
#include "Characters/PwnCharacterMovementComponent.h"
#include "Characters/PwnCharacterBase.h"
#include "Components/CapsuleComponent.h"
#include "Components/SplineComponent.h"
#include "GameplayModes/PwnGameplayModeSubsystem.h"
#include "GameplayModes/Combat/PwnCombatPlatformerPath.h"
@ -86,16 +87,24 @@ void UPwnCharacterMovementComponent::EnterSplineFollowMode() {
const UPwnGameplayModeSubsystem* Subsystem = GetWorld()->GetSubsystem<UPwnGameplayModeSubsystem>();
check(Subsystem);
FVector OutLocation;
APwnCombatPlatformerPath* OutCombatPath;
float OutDistanceAloneSpline;
if (Subsystem->FindClosestCombatPathLocation(UpdatedComponent->GetComponentLocation(), OutLocation, OutCombatPath, OutDistanceAloneSpline)) {
DistanceAlongSpline = OutDistanceAloneSpline;
if (Subsystem->FindClosestCombatPathLocation(UpdatedComponent->GetComponentLocation(), OutCombatPath)) {
CombatPath = OutCombatPath;
DotDirection = CombatPath->Reversed ? -1.0f : 1.0f;
FVector TargetLocation = CombatPath->Spline->GetLocationAtDistanceAlongSpline(DistanceAlongSpline, ESplineCoordinateSpace::World);
TargetLocation.Z = UpdatedComponent->GetComponentLocation().Z;
UpdatedComponent->SetWorldLocation(TargetLocation);
float ClosestInputKey = CombatPath->Spline->FindInputKeyClosestToWorldLocation(UpdatedComponent->GetComponentLocation());
FVector ClosestLocation = CombatPath->Spline->GetLocationAtSplineInputKey(ClosestInputKey, ESplineCoordinateSpace::World);
FHitResult Hit;
if (GetWorld()->LineTraceSingleByChannel(Hit, ClosestLocation, ClosestLocation + FVector(0.0f, 0.0f, -10000.0f),
ECC_Visibility, IGNORE_OWNER_PARAMS)) {
const float SplineKey = CombatPath->FlattenSpline->FindInputKeyClosestToWorldLocation(Hit.ImpactPoint);
DistanceAlongSpline = CombatPath->FlattenSpline->GetDistanceAlongSplineAtSplineInputKey(SplineKey);
ClosestLocation.Z += CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
UpdatedComponent->SetWorldLocation(ClosestLocation);
}
}
}
@ -109,7 +118,7 @@ bool UPwnCharacterMovementComponent::IsCustomMovementMode(const ECustomMovementM
}
void UPwnCharacterMovementComponent::RecomputeTangentAndAcceleration() {
Tangent2D = CombatPath->Spline->GetTangentAtDistanceAlongSpline(DistanceAlongSpline, ESplineCoordinateSpace::World).GetSafeNormal2D();
Tangent2D = CombatPath->FlattenSpline->GetTangentAtDistanceAlongSpline(DistanceAlongSpline, ESplineCoordinateSpace::World).GetSafeNormal2D();
// Recalculate acceleration so the input is relative to the spline
Acceleration = Tangent2D * Acceleration.Size2D() * FMath::Sign(Acceleration.X) * DotDirection;
}
@ -127,9 +136,9 @@ void UPwnCharacterMovementComponent::UpdatePawnVelocity(const float TimeTick) {
VelocityDirection = FMath::Sign(VelocityDirection); // -1, 0 or 1
float NewDistanceAlongSpline = DistanceAlongSpline + VelocityDirection * VelocitySize2D * TimeTick;
NewDistanceAlongSpline = FMath::Clamp(NewDistanceAlongSpline, 0.0f, CombatPath->Spline->GetSplineLength());
NewDistanceAlongSpline = FMath::Clamp(NewDistanceAlongSpline, 0.0f, CombatPath->FlattenSpline->GetSplineLength());
FVector TargetLocation = CombatPath->Spline->GetLocationAtDistanceAlongSpline(NewDistanceAlongSpline, ESplineCoordinateSpace::World);
FVector TargetLocation = CombatPath->FlattenSpline->GetLocationAtDistanceAlongSpline(NewDistanceAlongSpline, ESplineCoordinateSpace::World);
TargetLocation.Z = OldLocation.Z;
const FVector Direction = (TargetLocation - OldLocation).GetSafeNormal2D();
@ -142,18 +151,16 @@ void UPwnCharacterMovementComponent::UpdatePawnVelocity(const float TimeTick) {
void UPwnCharacterMovementComponent::UpdateDistanceAlongSplineAndLocation() {
// Maintain coherent distance along spline with location
FHitResult Hit;
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(GetOwner());
if (GetWorld()->LineTraceSingleByChannel(Hit, UpdatedComponent->GetComponentLocation(),
UpdatedComponent->GetComponentLocation() + FVector(0.0f, 0.0f, -10000.0f),
ECC_Visibility, QueryParams)) {
ECC_Visibility, IGNORE_OWNER_PARAMS)) {
FVector ImpactPoint = Hit.ImpactPoint;
const float InputKey = CombatPath->Spline->FindInputKeyClosestToWorldLocation(ImpactPoint);
DistanceAlongSpline = CombatPath->Spline->GetDistanceAlongSplineAtSplineInputKey(InputKey);
const float InputKey = CombatPath->FlattenSpline->FindInputKeyClosestToWorldLocation(ImpactPoint);
DistanceAlongSpline = CombatPath->FlattenSpline->GetDistanceAlongSplineAtSplineInputKey(InputKey);
}
FVector TargetLocation = CombatPath->Spline->GetLocationAtDistanceAlongSpline(DistanceAlongSpline, ESplineCoordinateSpace::World);
FVector TargetLocation = CombatPath->FlattenSpline->GetLocationAtDistanceAlongSpline(DistanceAlongSpline, ESplineCoordinateSpace::World);
TargetLocation.Z = UpdatedComponent->GetComponentLocation().Z;
UpdatedComponent->SetWorldLocation(TargetLocation);
}

View File

@ -7,6 +7,7 @@ APwnCombatPlatformerPath::APwnCombatPlatformerPath() {
PrimaryActorTick.bCanEverTick = false;
Spline = CreateDefaultSubobject<USplineComponent>(TEXT("Spline"));
Spline->ReparamStepsPerSegment = 100.0f;
SetRootComponent(Spline);
#if WITH_EDITORONLY_DATA
@ -20,24 +21,29 @@ void APwnCombatPlatformerPath::BeginPlay() {
check(Subsystem);
Subsystem->RegisterCombatPath(this);
FlattenSpline = NewObject<USplineComponent>(this, TEXT("FlattenSpline"));
FlattenSpline->SetClosedLoop(Spline->IsClosedLoop(), false);
FlattenSpline->ReparamStepsPerSegment = Spline->ReparamStepsPerSegment;
FlattenSpline->ClearSplinePoints(false);
const FVector FirstPointLocation = Spline->GetLocationAtSplinePoint(0, ESplineCoordinateSpace::World);
float FirstPointZ = FirstPointLocation.Z;
const float FirstPointZ = FirstPointLocation.Z;
const int32 PointsCount = Spline->GetNumberOfSplinePoints();
for (int i = 0; i < PointsCount; ++i) {
FVector NewLocation = Spline->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::World);
NewLocation.Z = FirstPointZ;
Spline->SetLocationAtSplinePoint(i, NewLocation, ESplineCoordinateSpace::World, false);
FlattenSpline->AddSplinePoint(NewLocation, ESplineCoordinateSpace::World, false);
FVector ArriveTangent = Spline->GetArriveTangentAtSplinePoint(i, ESplineCoordinateSpace::World);
FVector LeaveTangent = Spline->GetLeaveTangentAtSplinePoint(i, ESplineCoordinateSpace::World);
ArriveTangent.Z = 0;
LeaveTangent.Z = 0;
Spline->SetTangentsAtSplinePoint(i, ArriveTangent, LeaveTangent, ESplineCoordinateSpace::World, false);
FlattenSpline->SetTangentsAtSplinePoint(i, ArriveTangent, LeaveTangent, ESplineCoordinateSpace::World, false);
}
Spline->UpdateSpline();
FlattenSpline->UpdateSpline();
Super::BeginPlay();
}

View File

@ -41,11 +41,8 @@ void UPwnGameplayModeSubsystem::UnregisterCombatPath(APwnCombatPlatformerPath* C
CombatPaths.Remove(CombatPath);
}
bool UPwnGameplayModeSubsystem::FindClosestCombatPathLocation(const FVector& Location, FVector& OutCombatPathLocation,
APwnCombatPlatformerPath*& OutCombatPath, float& OutDistanceAlongSpline) const {
bool UPwnGameplayModeSubsystem::FindClosestCombatPathLocation(const FVector& Location, APwnCombatPlatformerPath*& OutCombatPath) const {
float ShortestDistance = FLT_MAX;
float ClosestKey = 0.0f;
FVector ClosestLocation = FVector::ZeroVector;
APwnCombatPlatformerPath* ClosestCombatPath = nullptr;
bool Found = false;
@ -57,17 +54,13 @@ bool UPwnGameplayModeSubsystem::FindClosestCombatPathLocation(const FVector& Loc
const float CurrentDistance = FVector::DistSquared(Location, CurrentLocation);
if (CurrentDistance < ShortestDistance) {
ShortestDistance = CurrentDistance;
ClosestKey = CurrentKey;
ClosestLocation = CurrentLocation;
ClosestCombatPath = CombatPath;
Found = true;
}
}
if (Found) {
OutCombatPathLocation = ClosestLocation;
OutCombatPath = ClosestCombatPath;
OutDistanceAlongSpline = OutCombatPath->Spline->GetDistanceAlongSplineAtSplineInputKey(ClosestKey);
}
return Found;
}

View File

@ -19,7 +19,7 @@ protected:
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
public:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Components")
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components")
TObjectPtr<USplineComponent> Spline;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Combat Platformer Path")
@ -27,4 +27,7 @@ public:
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Combat Platformer Path")
bool SwapCamera;
UPROPERTY(Transient, BlueprintReadOnly)
TObjectPtr<USplineComponent> FlattenSpline;
};

View File

@ -41,9 +41,8 @@ public:
UFUNCTION()
void UnregisterCombatPath(APwnCombatPlatformerPath* CombatPath);
UFUNCTION()
bool FindClosestCombatPathLocation(const FVector& Location, FVector& OutCombatPathLocation, APwnCombatPlatformerPath*& OutCombatPath,
float& OutDistanceAlongSpline) const;
UFUNCTION(BlueprintCallable)
bool FindClosestCombatPathLocation(const FVector& Location, APwnCombatPlatformerPath*& OutCombatPath) const;
public:
UPROPERTY(BlueprintAssignable)

View File

@ -10,3 +10,12 @@
#define BOOL_TO_TEXT(Bool) ((Bool) ? TEXT("True") : TEXT("False"))
#define BOOL_TO_STR(Bool) ((Bool) ? "True" : "False")
#define IGNORE_OWNER_PARAMS GetIgnoreActorParams(GetOwner())
#define IGNORE_THIS_PARAMS GetIgnoreActorParams(this)
inline FCollisionQueryParams GetIgnoreActorParams(const AActor* Actor) {
FCollisionQueryParams Params;
Params.AddIgnoredActor(Actor);
return Params;
}