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

View File

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

View File

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

View File

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

View File

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

View File

@ -10,3 +10,12 @@
#define BOOL_TO_TEXT(Bool) ((Bool) ? TEXT("True") : TEXT("False")) #define BOOL_TO_TEXT(Bool) ((Bool) ? TEXT("True") : TEXT("False"))
#define BOOL_TO_STR(Bool) ((Bool) ? "True" : "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;
}