Reculate flatten spline regulary

This commit is contained in:
Maxime Maurin 2023-11-25 16:50:06 +01:00
parent 6bf80a916e
commit 828faa777c
17 changed files with 109 additions and 37 deletions

Binary file not shown.

Binary file not shown.

View File

@ -86,7 +86,7 @@ void UPwnCharacterMovementComponent::EnterSplineFollowMode() {
IsFollowingSpline = true; IsFollowingSpline = true;
SetMovementMode(MOVE_Custom, SplineWalking); SetMovementMode(MOVE_Custom, SplineWalking);
UpdateCurrentCombatPath(true); UpdateCurrentCombatPath(true, true);
} }
void UPwnCharacterMovementComponent::ExitSplineFollowMode() { void UPwnCharacterMovementComponent::ExitSplineFollowMode() {
@ -99,25 +99,35 @@ bool UPwnCharacterMovementComponent::IsCustomMovementMode(const ECustomMovementM
return MovementMode == MOVE_Custom && CustomMovementMode == Mode; return MovementMode == MOVE_Custom && CustomMovementMode == Mode;
} }
bool UPwnCharacterMovementComponent::LineTraceToGround(FHitResult& OutHit, const FVector& StartLocation) const { bool UPwnCharacterMovementComponent::LineTraceToGround(FHitResult& OutHit, const FVector& StartLocation, const FLinearColor& DebugColor) const {
const FVector EndLocation = StartLocation + FVector(0.0f, 0.0f, -LineTraceDistance); const FVector EndLocation = StartLocation + FVector(0.0f, 0.0f, -LineTraceDistance);
return UKismetSystemLibrary::LineTraceSingle(this, StartLocation, EndLocation, UEngineTypes::ConvertToTraceType(ECC_Visibility), false, TArray<AActor*>(), return UKismetSystemLibrary::LineTraceSingle(this, StartLocation, EndLocation, UEngineTypes::ConvertToTraceType(ECC_Visibility), false, TArray<AActor*>(),
EDrawDebugTrace::None, OutHit, true, FLinearColor::Red, FLinearColor::Green, 0.5f); DebugColor == FLinearColor::White ? EDrawDebugTrace::None : EDrawDebugTrace::ForDuration, OutHit, true, DebugColor, FLinearColor::Green, 0.5f);
} }
float AccumulatedTimer = 0.0f;
void UPwnCharacterMovementComponent::UpdateCurrentCombatPath(const bool UpdateLocation) { void UPwnCharacterMovementComponent::UpdateCurrentCombatPath(const bool Force, const bool UpdateLocation) {
AccumulatedTimer += GetWorld()->GetDeltaSeconds();
if (AccumulatedTimer < 0.3f && !Force) {
return;
}
AccumulatedTimer = 0.0f;
APwnCombatPlatformerPath* OutCombatPath; APwnCombatPlatformerPath* OutCombatPath;
FHitResult Hit; FHitResult Hit;
if (LineTraceToGround(Hit, UpdatedComponent->GetComponentLocation()) float ClosestInputKey = -1.0f;
if (LineTraceToGround(Hit, UpdatedComponent->GetComponentLocation(), FLinearColor::Red)) {
UE_LOG(LogTemp, Log, TEXT("Hit location : %s"), *Hit.ImpactPoint.ToString());
}
if (LineTraceToGround(Hit, UpdatedComponent->GetComponentLocation(), FLinearColor::Red)
&& UPwnGameplayModeSubsystem::Get(this).FindClosestCombatPathLocation(Hit.ImpactPoint, OutCombatPath) && UPwnGameplayModeSubsystem::Get(this).FindClosestCombatPathLocation(Hit.ImpactPoint, OutCombatPath)
&& OutCombatPath != CombatPath) { && OutCombatPath != CombatPath) {
CombatPath = OutCombatPath; CombatPath = OutCombatPath;
DotDirection = CombatPath->Reversed ? -1.0f : 1.0f; DotDirection = CombatPath->Reversed ? -1.0f : 1.0f;
const float ClosestInputKey = CombatPath->Spline->FindInputKeyClosestToWorldLocation(UpdatedComponent->GetComponentLocation()); ClosestInputKey = CombatPath->Spline->FindInputKeyClosestToWorldLocation(UpdatedComponent->GetComponentLocation());
const FVector ClosestLocation = CombatPath->Spline->GetLocationAtSplineInputKey(ClosestInputKey, ESplineCoordinateSpace::World); const FVector ClosestLocation = CombatPath->Spline->GetLocationAtSplineInputKey(ClosestInputKey, ESplineCoordinateSpace::World);
if (LineTraceToGround(Hit, ClosestLocation)) { if (LineTraceToGround(Hit, ClosestLocation, FLinearColor::Blue)) {
const float SplineKey = CombatPath->FlattenedSpline->FindInputKeyClosestToWorldLocation(Hit.ImpactPoint); const float SplineKey = CombatPath->FlattenedSpline->FindInputKeyClosestToWorldLocation(Hit.ImpactPoint);
DistanceAlongSpline = CombatPath->FlattenedSpline->GetDistanceAlongSplineAtSplineInputKey(SplineKey); DistanceAlongSpline = CombatPath->FlattenedSpline->GetDistanceAlongSplineAtSplineInputKey(SplineKey);
@ -128,6 +138,14 @@ void UPwnCharacterMovementComponent::UpdateCurrentCombatPath(const bool UpdateLo
} }
} }
} }
check(CombatPath);
// If the combat path was the same as before, the closest input key will has not been computed
if (ClosestInputKey < 0.0f) {
ClosestInputKey = CombatPath->Spline->FindInputKeyClosestToWorldLocation(UpdatedComponent->GetComponentLocation());
}
CombatPath->UpdateFlattenSpline(ClosestInputKey);
} }
void UPwnCharacterMovementComponent::UpdateTangentAndAcceleration() { void UPwnCharacterMovementComponent::UpdateTangentAndAcceleration() {
@ -163,7 +181,7 @@ void UPwnCharacterMovementComponent::UpdatePawnVelocity(const float TimeTick) {
void UPwnCharacterMovementComponent::UpdateDistanceAlongSpline() { void UPwnCharacterMovementComponent::UpdateDistanceAlongSpline() {
FHitResult Hit; FHitResult Hit;
if (LineTraceToGround(Hit, UpdatedComponent->GetComponentLocation())) { if (LineTraceToGround(Hit, UpdatedComponent->GetComponentLocation(), FLinearColor::White)) {
const FVector ImpactPoint = Hit.ImpactPoint; const FVector ImpactPoint = Hit.ImpactPoint;
const float InputKey = CombatPath->FlattenedSpline->FindInputKeyClosestToWorldLocation(ImpactPoint); const float InputKey = CombatPath->FlattenedSpline->FindInputKeyClosestToWorldLocation(ImpactPoint);
DistanceAlongSpline = CombatPath->FlattenedSpline->GetDistanceAlongSplineAtSplineInputKey(InputKey); DistanceAlongSpline = CombatPath->FlattenedSpline->GetDistanceAlongSplineAtSplineInputKey(InputKey);
@ -378,7 +396,7 @@ void UPwnCharacterMovementComponent::PhysSplineWalking(const float DeltaTime, in
/* -- PAWN MODIFICATIONS -- */ /* -- PAWN MODIFICATIONS -- */
UpdateDistanceAlongSpline(); UpdateDistanceAlongSpline();
UpdateLocationOnFlattenedSpline(); //UpdateLocationOnFlattenedSpline();
} }
void UPwnCharacterMovementComponent::PhysSplineFalling(const float DeltaTime, int32 Iterations) { void UPwnCharacterMovementComponent::PhysSplineFalling(const float DeltaTime, int32 Iterations) {

View File

@ -3,6 +3,8 @@
#include "Components/SplineComponent.h" #include "Components/SplineComponent.h"
#include "GameplayModes/PwnGameplayModeSubsystem.h" #include "GameplayModes/PwnGameplayModeSubsystem.h"
constexpr int FlattenSplinePadding = 2;
APwnCombatPlatformerPath::APwnCombatPlatformerPath() { APwnCombatPlatformerPath::APwnCombatPlatformerPath() {
PrimaryActorTick.bCanEverTick = false; PrimaryActorTick.bCanEverTick = false;
@ -16,21 +18,26 @@ APwnCombatPlatformerPath::APwnCombatPlatformerPath() {
#endif #endif
} }
void APwnCombatPlatformerPath::BeginPlay() { void APwnCombatPlatformerPath::UpdateFlattenSpline(const float InputKey) {
UPwnGameplayModeSubsystem* Subsystem = GetWorld()->GetSubsystem<UPwnGameplayModeSubsystem>(); const int32 SplinePointCounts = Spline->GetNumberOfSplinePoints();
check(Subsystem); const int32 NewMinKey = FMath::Clamp(FMath::CeilToInt(InputKey) - FlattenSplinePadding, 0, SplinePointCounts - 1);
Subsystem->RegisterCombatPath(this); const int32 NewMaxKey = FMath::Clamp(FMath::FloorToInt(InputKey) + FlattenSplinePadding, 0, SplinePointCounts - 1);
if (NewMinKey == MinKey && NewMaxKey == MaxKey) {
// Already up to date
return;
}
MinKey = NewMinKey;
MaxKey = NewMaxKey;
FlattenedSpline = NewObject<USplineComponent>(this, TEXT("FlattenedSpline"));
FlattenedSpline->SetClosedLoop(Spline->IsClosedLoop(), false);
FlattenedSpline->ReparamStepsPerSegment = Spline->ReparamStepsPerSegment;
FlattenedSpline->ClearSplinePoints(false); FlattenedSpline->ClearSplinePoints(false);
const FVector FirstPointLocation = Spline->GetLocationAtSplinePoint(0, ESplineCoordinateSpace::World); const FVector FirstPointLocation = Spline->GetLocationAtSplinePoint(MinKey, ESplineCoordinateSpace::World);
const float FirstPointZ = FirstPointLocation.Z; const float FirstPointZ = FirstPointLocation.Z;
const int32 PointsCount = Spline->GetNumberOfSplinePoints(); int32 PointIndex = 0;
for (int i = 0; i < PointsCount; ++i) { for (int i = MinKey; i <= MaxKey; ++i, ++PointIndex) {
FVector NewLocation = Spline->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::World); FVector NewLocation = Spline->GetLocationAtSplinePoint(i, ESplineCoordinateSpace::World);
NewLocation.Z = FirstPointZ; NewLocation.Z = FirstPointZ;
FlattenedSpline->AddSplinePoint(NewLocation, ESplineCoordinateSpace::World, false); FlattenedSpline->AddSplinePoint(NewLocation, ESplineCoordinateSpace::World, false);
@ -40,11 +47,23 @@ void APwnCombatPlatformerPath::BeginPlay() {
ArriveTangent.Z = 0; ArriveTangent.Z = 0;
LeaveTangent.Z = 0; LeaveTangent.Z = 0;
FlattenedSpline->SetTangentsAtSplinePoint(i, ArriveTangent, LeaveTangent, ESplineCoordinateSpace::World, false); FlattenedSpline->SetTangentsAtSplinePoint(PointIndex, ArriveTangent, LeaveTangent, ESplineCoordinateSpace::World, false);
} }
FlattenedSpline->UpdateSpline(); FlattenedSpline->UpdateSpline();
}
void APwnCombatPlatformerPath::BeginPlay() {
UPwnGameplayModeSubsystem* Subsystem = GetWorld()->GetSubsystem<UPwnGameplayModeSubsystem>();
check(Subsystem);
Subsystem->RegisterCombatPath(this);
FlattenedSpline = NewObject<USplineComponent>(this, TEXT("FlattenedSpline"));
FlattenedSpline->SetClosedLoop(Spline->IsClosedLoop(), false);
FlattenedSpline->ReparamStepsPerSegment = Spline->ReparamStepsPerSegment;
UpdateFlattenSpline(0.0f);
Super::BeginPlay(); Super::BeginPlay();
} }

View File

@ -2,6 +2,7 @@
#include "Components/SplineComponent.h" #include "Components/SplineComponent.h"
#include "GameplayModes/Combat/PwnCombatPlatformerPath.h" #include "GameplayModes/Combat/PwnCombatPlatformerPath.h"
#include "Utils/EngineUtils.h"
UPwnGameplayModeSubsystem& UPwnGameplayModeSubsystem::Get(const UObject* WorldContextObject) { UPwnGameplayModeSubsystem& UPwnGameplayModeSubsystem::Get(const UObject* WorldContextObject) {
const UWorld* World = GEngine->GetWorldFromContextObjectChecked(WorldContextObject); const UWorld* World = GEngine->GetWorldFromContextObjectChecked(WorldContextObject);
@ -57,16 +58,21 @@ bool UPwnGameplayModeSubsystem::FindClosestCombatPathLocation(const FVector& Loc
const float CurrentKey = CurrentSpline->FindInputKeyClosestToWorldLocation(Location); const float CurrentKey = CurrentSpline->FindInputKeyClosestToWorldLocation(Location);
FVector CurrentLocation = CurrentSpline->GetLocationAtSplineInputKey(CurrentKey, ESplineCoordinateSpace::World); FVector CurrentLocation = CurrentSpline->GetLocationAtSplineInputKey(CurrentKey, ESplineCoordinateSpace::World);
const float CurrentDistance = FVector::DistSquared(Location, CurrentLocation); if (CurrentLocation.Z < Location.Z) {
if (CurrentDistance < ShortestDistance) { continue;
ShortestDistance = CurrentDistance;
ClosestCombatPath = CombatPath;
} }
const float CurrentDistance = FVector::DistSquared(Location, CurrentLocation);
if (CurrentDistance >= ShortestDistance) {
continue;
}
ShortestDistance = CurrentDistance;
ClosestCombatPath = CombatPath;
} }
if (ClosestCombatPath != nullptr) { if (ClosestCombatPath != nullptr) {
OutCombatPath = ClosestCombatPath; OutCombatPath = ClosestCombatPath;
return true; return true;
} }
PRINT_STRING_RED("Aie");
return false; return false;
} }

View File

@ -51,9 +51,9 @@ public:
bool IsCustomMovementMode(const ECustomMovementMode Mode) const; bool IsCustomMovementMode(const ECustomMovementMode Mode) const;
private: private:
bool LineTraceToGround(FHitResult& OutHit, const FVector& StartLocation) const; bool LineTraceToGround(FHitResult& OutHit, const FVector& StartLocation, const FLinearColor& DebugColor) const;
void UpdateCurrentCombatPath(const bool UpdateLocation = false); void UpdateCurrentCombatPath(bool Force = false, const bool UpdateLocation = false);
/** /**
* Updates the tangent in function of the current distance along the spline. Then updates the acceleration so it will simulate an input in the * Updates the tangent in function of the current distance along the spline. Then updates the acceleration so it will simulate an input in the

View File

@ -13,6 +13,8 @@ class PAWN_API APwnCombatPlatformerPath : public AActor {
public: public:
APwnCombatPlatformerPath(); APwnCombatPlatformerPath();
void UpdateFlattenSpline(const float InputKey);
protected: protected:
virtual void BeginPlay() override; virtual void BeginPlay() override;
@ -30,4 +32,10 @@ public:
UPROPERTY(Transient, BlueprintReadOnly) UPROPERTY(Transient, BlueprintReadOnly)
TObjectPtr<USplineComponent> FlattenedSpline; TObjectPtr<USplineComponent> FlattenedSpline;
UPROPERTY()
int32 MinKey;
UPROPERTY()
int32 MaxKey;
}; };