Document character movement component code
This commit is contained in:
parent
028e228c8f
commit
aedd5ee35e
BIN
Pawn_Unreal/Content/Characters/BP_Judy.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/Characters/BP_Judy.uasset
(Stored with Git LFS)
Binary file not shown.
BIN
Pawn_Unreal/Content/Systems/Camera/BP_MainCameraManager.uasset
(Stored with Git LFS)
BIN
Pawn_Unreal/Content/Systems/Camera/BP_MainCameraManager.uasset
(Stored with Git LFS)
Binary file not shown.
@ -7,6 +7,8 @@
|
|||||||
#include "GameplayModes/Combat/PwnCombatPlatformerPath.h"
|
#include "GameplayModes/Combat/PwnCombatPlatformerPath.h"
|
||||||
#include "Utils/EngineUtils.h"
|
#include "Utils/EngineUtils.h"
|
||||||
|
|
||||||
|
constexpr float LineTraceDistance = 10000.0f;
|
||||||
|
|
||||||
UPwnCharacterMovementComponent::UPwnCharacterMovementComponent() {
|
UPwnCharacterMovementComponent::UPwnCharacterMovementComponent() {
|
||||||
PrimaryComponentTick.bCanEverTick = true;
|
PrimaryComponentTick.bCanEverTick = true;
|
||||||
}
|
}
|
||||||
@ -45,19 +47,19 @@ bool UPwnCharacterMovementComponent::IsFalling() const {
|
|||||||
return Super::IsFalling() || IsCustomMovementMode(SplineFalling);
|
return Super::IsFalling() || IsCustomMovementMode(SplineFalling);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UPwnCharacterMovementComponent::OnMovementModeChanged(EMovementMode PreviousMovementMode, uint8 PreviousCustomMode) {
|
void UPwnCharacterMovementComponent::OnMovementModeChanged(const EMovementMode PreviousMovementMode, const uint8 PreviousCustomMode) {
|
||||||
Super::OnMovementModeChanged(PreviousMovementMode, PreviousCustomMode);
|
Super::OnMovementModeChanged(PreviousMovementMode, PreviousCustomMode);
|
||||||
|
|
||||||
// React to changes in the movement mode.
|
// React to changes in the movement mode
|
||||||
if (MovementMode == MOVE_Custom && CustomMovementMode == SplineWalking) {
|
if (MovementMode == MOVE_Custom && CustomMovementMode == SplineWalking) {
|
||||||
// make sure we update our new floor/base on initial entry of the walking physics
|
// Make sure we update our new floor/base on initial entry of the walking physics
|
||||||
FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, false);
|
FindFloor(UpdatedComponent->GetComponentLocation(), CurrentFloor, false);
|
||||||
AdjustFloorHeight();
|
AdjustFloorHeight();
|
||||||
SetBaseFromFloor(CurrentFloor);
|
SetBaseFromFloor(CurrentFloor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UPwnCharacterMovementComponent::UpdateCharacterStateBeforeMovement(float DeltaSeconds) {
|
void UPwnCharacterMovementComponent::UpdateCharacterStateBeforeMovement(const float DeltaSeconds) {
|
||||||
if (MovementMode == MOVE_Falling && IsFollowingSpline) {
|
if (MovementMode == MOVE_Falling && IsFollowingSpline) {
|
||||||
SetMovementMode(MOVE_Custom, SplineFalling);
|
SetMovementMode(MOVE_Custom, SplineFalling);
|
||||||
} else if (MovementMode == MOVE_Walking && IsFollowingSpline) {
|
} else if (MovementMode == MOVE_Walking && IsFollowingSpline) {
|
||||||
@ -93,14 +95,14 @@ void UPwnCharacterMovementComponent::EnterSplineFollowMode() {
|
|||||||
CombatPath = OutCombatPath;
|
CombatPath = OutCombatPath;
|
||||||
DotDirection = CombatPath->Reversed ? -1.0f : 1.0f;
|
DotDirection = CombatPath->Reversed ? -1.0f : 1.0f;
|
||||||
|
|
||||||
float ClosestInputKey = CombatPath->Spline->FindInputKeyClosestToWorldLocation(UpdatedComponent->GetComponentLocation());
|
const float ClosestInputKey = CombatPath->Spline->FindInputKeyClosestToWorldLocation(UpdatedComponent->GetComponentLocation());
|
||||||
FVector ClosestLocation = CombatPath->Spline->GetLocationAtSplineInputKey(ClosestInputKey, ESplineCoordinateSpace::World);
|
FVector ClosestLocation = CombatPath->Spline->GetLocationAtSplineInputKey(ClosestInputKey, ESplineCoordinateSpace::World);
|
||||||
|
|
||||||
FHitResult Hit;
|
FHitResult Hit;
|
||||||
if (GetWorld()->LineTraceSingleByChannel(Hit, ClosestLocation, ClosestLocation + FVector(0.0f, 0.0f, -10000.0f),
|
if (GetWorld()->LineTraceSingleByChannel(Hit, ClosestLocation, ClosestLocation + FVector(0.0f, 0.0f, -LineTraceDistance),
|
||||||
ECC_Visibility, IGNORE_OWNER_PARAMS)) {
|
ECC_Visibility, IGNORE_OWNER_PARAMS)) {
|
||||||
const float SplineKey = CombatPath->FlattenSpline->FindInputKeyClosestToWorldLocation(Hit.ImpactPoint);
|
const float SplineKey = CombatPath->FlattenedSpline->FindInputKeyClosestToWorldLocation(Hit.ImpactPoint);
|
||||||
DistanceAlongSpline = CombatPath->FlattenSpline->GetDistanceAlongSplineAtSplineInputKey(SplineKey);
|
DistanceAlongSpline = CombatPath->FlattenedSpline->GetDistanceAlongSplineAtSplineInputKey(SplineKey);
|
||||||
|
|
||||||
ClosestLocation.Z += CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
|
ClosestLocation.Z += CharacterOwner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
|
||||||
UpdatedComponent->SetWorldLocation(ClosestLocation);
|
UpdatedComponent->SetWorldLocation(ClosestLocation);
|
||||||
@ -117,8 +119,8 @@ bool UPwnCharacterMovementComponent::IsCustomMovementMode(const ECustomMovementM
|
|||||||
return MovementMode == MOVE_Custom && CustomMovementMode == Mode;
|
return MovementMode == MOVE_Custom && CustomMovementMode == Mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UPwnCharacterMovementComponent::RecomputeTangentAndAcceleration() {
|
void UPwnCharacterMovementComponent::UpdateTangentAndAcceleration() {
|
||||||
Tangent2D = CombatPath->FlattenSpline->GetTangentAtDistanceAlongSpline(DistanceAlongSpline, ESplineCoordinateSpace::World).GetSafeNormal2D();
|
Tangent2D = CombatPath->FlattenedSpline->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;
|
||||||
}
|
}
|
||||||
@ -135,32 +137,31 @@ 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;
|
DistanceAlongSpline = DistanceAlongSpline + VelocityDirection * VelocitySize2D * TimeTick;
|
||||||
NewDistanceAlongSpline = FMath::Clamp(NewDistanceAlongSpline, 0.0f, CombatPath->FlattenSpline->GetSplineLength());
|
DistanceAlongSpline = FMath::Clamp(DistanceAlongSpline, 0.0f, CombatPath->FlattenedSpline->GetSplineLength());
|
||||||
|
|
||||||
FVector TargetLocation = CombatPath->FlattenSpline->GetLocationAtDistanceAlongSpline(NewDistanceAlongSpline, ESplineCoordinateSpace::World);
|
FVector TargetLocation = CombatPath->FlattenedSpline->GetLocationAtDistanceAlongSpline(DistanceAlongSpline, ESplineCoordinateSpace::World);
|
||||||
TargetLocation.Z = OldLocation.Z;
|
TargetLocation.Z = OldLocation.Z;
|
||||||
|
|
||||||
const FVector Direction = (TargetLocation - OldLocation).GetSafeNormal2D();
|
const FVector Direction = (TargetLocation - OldLocation).GetSafeNormal2D();
|
||||||
Velocity = VelocitySize2D * Direction;
|
Velocity = VelocitySize2D * Direction;
|
||||||
Velocity.Z = OldVelocity.Z;
|
Velocity.Z = OldVelocity.Z;
|
||||||
|
|
||||||
DistanceAlongSpline = NewDistanceAlongSpline;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UPwnCharacterMovementComponent::UpdateDistanceAlongSplineAndLocation() {
|
void UPwnCharacterMovementComponent::UpdateDistanceAlongSpline() {
|
||||||
// Maintain coherent distance along spline with location
|
|
||||||
FHitResult Hit;
|
FHitResult Hit;
|
||||||
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, -LineTraceDistance),
|
||||||
ECC_Visibility, IGNORE_OWNER_PARAMS)) {
|
ECC_Visibility, IGNORE_OWNER_PARAMS)) {
|
||||||
|
const FVector ImpactPoint = Hit.ImpactPoint;
|
||||||
FVector ImpactPoint = Hit.ImpactPoint;
|
const float InputKey = CombatPath->FlattenedSpline->FindInputKeyClosestToWorldLocation(ImpactPoint);
|
||||||
const float InputKey = CombatPath->FlattenSpline->FindInputKeyClosestToWorldLocation(ImpactPoint);
|
DistanceAlongSpline = CombatPath->FlattenedSpline->GetDistanceAlongSplineAtSplineInputKey(InputKey);
|
||||||
DistanceAlongSpline = CombatPath->FlattenSpline->GetDistanceAlongSplineAtSplineInputKey(InputKey);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FVector TargetLocation = CombatPath->FlattenSpline->GetLocationAtDistanceAlongSpline(DistanceAlongSpline, ESplineCoordinateSpace::World);
|
void UPwnCharacterMovementComponent::UpdateLocationOnFlattenedSpline() const {
|
||||||
|
// Maintain coherent distance along spline with location
|
||||||
|
FVector TargetLocation = CombatPath->FlattenedSpline->GetLocationAtDistanceAlongSpline(DistanceAlongSpline, ESplineCoordinateSpace::World);
|
||||||
TargetLocation.Z = UpdatedComponent->GetComponentLocation().Z;
|
TargetLocation.Z = UpdatedComponent->GetComponentLocation().Z;
|
||||||
UpdatedComponent->SetWorldLocation(TargetLocation);
|
UpdatedComponent->SetWorldLocation(TargetLocation);
|
||||||
}
|
}
|
||||||
@ -202,7 +203,7 @@ void UPwnCharacterMovementComponent::PhysSplineWalking(const float DeltaTime, in
|
|||||||
const FVector OldLocation = UpdatedComponent->GetComponentLocation();
|
const FVector OldLocation = UpdatedComponent->GetComponentLocation();
|
||||||
const FFindFloorResult OldFloor = CurrentFloor;
|
const FFindFloorResult OldFloor = CurrentFloor;
|
||||||
|
|
||||||
RecomputeTangentAndAcceleration(); /* -- PAWN MODIFICATIONS -- */
|
UpdateTangentAndAcceleration(); /* -- PAWN MODIFICATIONS -- */
|
||||||
Acceleration.Z = 0.f;
|
Acceleration.Z = 0.f;
|
||||||
|
|
||||||
RestorePreAdditiveRootMotionVelocity();
|
RestorePreAdditiveRootMotionVelocity();
|
||||||
@ -362,7 +363,9 @@ void UPwnCharacterMovementComponent::PhysSplineWalking(const float DeltaTime, in
|
|||||||
MaintainHorizontalGroundVelocity();
|
MaintainHorizontalGroundVelocity();
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateDistanceAlongSplineAndLocation(); /* -- PAWN MODIFICATIONS -- */
|
/* -- PAWN MODIFICATIONS -- */
|
||||||
|
UpdateDistanceAlongSpline();
|
||||||
|
UpdateLocationOnFlattenedSpline();
|
||||||
}
|
}
|
||||||
|
|
||||||
UE_DISABLE_OPTIMIZATION
|
UE_DISABLE_OPTIMIZATION
|
||||||
@ -372,7 +375,7 @@ void UPwnCharacterMovementComponent::PhysSplineFalling(const float DeltaTime, in
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RecomputeTangentAndAcceleration(); /* -- PAWN MODIFICATIONS -- */
|
UpdateTangentAndAcceleration(); /* -- PAWN MODIFICATIONS -- */
|
||||||
|
|
||||||
FVector FallAcceleration = GetFallingLateralAcceleration(DeltaTime);
|
FVector FallAcceleration = GetFallingLateralAcceleration(DeltaTime);
|
||||||
FallAcceleration.Z = 0.f;
|
FallAcceleration.Z = 0.f;
|
||||||
@ -676,7 +679,9 @@ void UPwnCharacterMovementComponent::PhysSplineFalling(const float DeltaTime, in
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateDistanceAlongSplineAndLocation(); /* -- PAWN MODIFICATIONS -- */
|
/* -- PAWN MODIFICATIONS -- */
|
||||||
|
UpdateDistanceAlongSpline();
|
||||||
|
UpdateLocationOnFlattenedSpline();
|
||||||
}
|
}
|
||||||
|
|
||||||
UE_ENABLE_OPTIMIZATION
|
UE_ENABLE_OPTIMIZATION
|
||||||
|
|||||||
@ -21,10 +21,10 @@ void APwnCombatPlatformerPath::BeginPlay() {
|
|||||||
check(Subsystem);
|
check(Subsystem);
|
||||||
Subsystem->RegisterCombatPath(this);
|
Subsystem->RegisterCombatPath(this);
|
||||||
|
|
||||||
FlattenSpline = NewObject<USplineComponent>(this, TEXT("FlattenSpline"));
|
FlattenedSpline = NewObject<USplineComponent>(this, TEXT("FlattenedSpline"));
|
||||||
FlattenSpline->SetClosedLoop(Spline->IsClosedLoop(), false);
|
FlattenedSpline->SetClosedLoop(Spline->IsClosedLoop(), false);
|
||||||
FlattenSpline->ReparamStepsPerSegment = Spline->ReparamStepsPerSegment;
|
FlattenedSpline->ReparamStepsPerSegment = Spline->ReparamStepsPerSegment;
|
||||||
FlattenSpline->ClearSplinePoints(false);
|
FlattenedSpline->ClearSplinePoints(false);
|
||||||
|
|
||||||
const FVector FirstPointLocation = Spline->GetLocationAtSplinePoint(0, ESplineCoordinateSpace::World);
|
const FVector FirstPointLocation = Spline->GetLocationAtSplinePoint(0, ESplineCoordinateSpace::World);
|
||||||
const float FirstPointZ = FirstPointLocation.Z;
|
const float FirstPointZ = FirstPointLocation.Z;
|
||||||
@ -33,17 +33,17 @@ void APwnCombatPlatformerPath::BeginPlay() {
|
|||||||
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;
|
||||||
FlattenSpline->AddSplinePoint(NewLocation, ESplineCoordinateSpace::World, false);
|
FlattenedSpline->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;
|
||||||
FlattenSpline->SetTangentsAtSplinePoint(i, ArriveTangent, LeaveTangent, ESplineCoordinateSpace::World, false);
|
FlattenedSpline->SetTangentsAtSplinePoint(i, ArriveTangent, LeaveTangent, ESplineCoordinateSpace::World, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
FlattenSpline->UpdateSpline();
|
FlattenedSpline->UpdateSpline();
|
||||||
|
|
||||||
Super::BeginPlay();
|
Super::BeginPlay();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,18 +44,47 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable, Category="CharacterMovement")
|
UFUNCTION(BlueprintCallable, Category="CharacterMovement")
|
||||||
void ExitSplineFollowMode();
|
void ExitSplineFollowMode();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return True if the movement component is in the specified custom movement mode.
|
||||||
|
*/
|
||||||
UFUNCTION(BlueprintCallable, Category="CharacterMovement")
|
UFUNCTION(BlueprintCallable, Category="CharacterMovement")
|
||||||
bool IsCustomMovementMode(const ECustomMovementMode Mode) const;
|
bool IsCustomMovementMode(const ECustomMovementMode Mode) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RecomputeTangentAndAcceleration();
|
/**
|
||||||
|
* Updates the tangent in function of the current distance along the spline. Then updates the acceleration so it will simulate an input in the
|
||||||
|
* direction of the tangent.
|
||||||
|
*/
|
||||||
|
void UpdateTangentAndAcceleration();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the distance along the spline in function of the current velocity. Then updates the velocity so the Updated Component will move
|
||||||
|
* to the next location on the spline.
|
||||||
|
* @param TimeTick Delta time in seconds for this update
|
||||||
|
*/
|
||||||
void UpdatePawnVelocity(const float TimeTick);
|
void UpdatePawnVelocity(const float TimeTick);
|
||||||
|
|
||||||
void UpdateDistanceAlongSplineAndLocation();
|
/**
|
||||||
|
* Updates the distance along the spline.
|
||||||
|
* Trace a line from the current location of the Updated Component to the ground. Retrieves the closest point on the flattened spline to the
|
||||||
|
* intersection point. The distance along the spline is then updated.
|
||||||
|
*/
|
||||||
|
void UpdateDistanceAlongSpline();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the location of the Updated Component to match the current distance along the spline. Must be called once the distance along the spline
|
||||||
|
* has been updated.
|
||||||
|
*/
|
||||||
|
void UpdateLocationOnFlattenedSpline() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom movement update so the Updated Component follows the spline. Same behavior as walking on the ground.
|
||||||
|
*/
|
||||||
void PhysSplineWalking(const float DeltaTime, int32 Iterations);
|
void PhysSplineWalking(const float DeltaTime, int32 Iterations);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom movement update so the Updated Component falls along the spline. Same behavior as falling.
|
||||||
|
*/
|
||||||
void PhysSplineFalling(const float DeltaTime, int32 Iterations);
|
void PhysSplineFalling(const float DeltaTime, int32 Iterations);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|||||||
@ -29,5 +29,5 @@ public:
|
|||||||
bool SwapCamera;
|
bool SwapCamera;
|
||||||
|
|
||||||
UPROPERTY(Transient, BlueprintReadOnly)
|
UPROPERTY(Transient, BlueprintReadOnly)
|
||||||
TObjectPtr<USplineComponent> FlattenSpline;
|
TObjectPtr<USplineComponent> FlattenedSpline;
|
||||||
};
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user