diff --git a/Source/TengriPlatformer/Movement/TengriMovementComponent.cpp b/Source/TengriPlatformer/Movement/TengriMovementComponent.cpp index ca70e52..5eb00c1 100644 --- a/Source/TengriPlatformer/Movement/TengriMovementComponent.cpp +++ b/Source/TengriPlatformer/Movement/TengriMovementComponent.cpp @@ -313,33 +313,49 @@ void UTengriMovementComponent::TickPhysics( const float CurrentZ = PhysicsVelocity.Z; FVector HorizontalVelocity(PhysicsVelocity.X, PhysicsVelocity.Y, 0.f); - // Select Acceleration/Friction based on state - const float CurrentAccel = bIsGrounded - ? MovementConfig->Acceleration - : (MovementConfig->Acceleration * MovementConfig->AirControl); - const float CurrentFriction = bIsGrounded ? MovementConfig->Friction : MovementConfig->AirFriction; if (!InputVector.IsNearlyZero()) { + // Calculate directional air control modifier + // Reduce control when trying to reverse direction mid-air + const FVector VelocityDir = HorizontalVelocity.GetSafeNormal(); + const float Dot = FVector::DotProduct(VelocityDir, InputVector); + + float FinalAirControl = MovementConfig->AirControl; + + // Reduce braking effectiveness in air (prevents instant direction changes) + if (Dot < 0.0f) + { + FinalAirControl *= 0.5f; + } + + const float CurrentAccel = MovementConfig->Acceleration * FinalAirControl; const FVector TargetVelocity = InputVector * MovementConfig->MaxSpeed; - HorizontalVelocity = FMath::VInterpTo( - HorizontalVelocity, - TargetVelocity, - FixedDeltaTime, - CurrentAccel // <-- Uses Air Control if flying - ); + + if (CurrentAccel > KINDA_SMALL_NUMBER) + { + HorizontalVelocity = FMath::VInterpTo( + HorizontalVelocity, + TargetVelocity, + FixedDeltaTime, + CurrentAccel + ); + } } else { - HorizontalVelocity = FMath::VInterpTo( - HorizontalVelocity, - FVector::ZeroVector, - FixedDeltaTime, - CurrentFriction // <-- Usually 0 in air - ); + if (CurrentFriction > KINDA_SMALL_NUMBER) + { + HorizontalVelocity = FMath::VInterpTo( + HorizontalVelocity, + FVector::ZeroVector, + FixedDeltaTime, + CurrentFriction + ); + } } PhysicsVelocity = HorizontalVelocity; @@ -450,8 +466,8 @@ void UTengriMovementComponent::TickPhysics( FHitResult SnapHit; bJustSnapped = PerformGroundSnapping(PhysicsLocation, SnapHit); - // Project velocity onto slope if snapped - if (bJustSnapped && !InputVector.IsNearlyZero()) + // Always project velocity onto slope when snapped (preserves momentum) + if (bJustSnapped) { PhysicsVelocity = UTengriCollisionResolver::ProjectVelocity( PhysicsVelocity, @@ -571,8 +587,8 @@ bool UTengriMovementComponent::PerformGroundSnapping( void UTengriMovementComponent::ForceRotation(const FRotator& NewRotation) { - // Обновляем все внутренние состояния, чтобы физика "подхватила" новый поворот + // Update all internal states so physics adopts new rotation immediately PhysicsRotation = NewRotation; RenderRotation = NewRotation; - PreviousPhysicsRotation = NewRotation; // Сбрасываем интерполяцию + PreviousPhysicsRotation = NewRotation; // Reset interpolation } \ No newline at end of file diff --git a/Source/TengriPlatformer/Movement/TengriMovementComponent.h b/Source/TengriPlatformer/Movement/TengriMovementComponent.h index 0730958..de7aa05 100644 --- a/Source/TengriPlatformer/Movement/TengriMovementComponent.h +++ b/Source/TengriPlatformer/Movement/TengriMovementComponent.h @@ -32,6 +32,10 @@ class TENGRIPLATFORMER_API UTengriMovementComponent : public UActorComponent public: UTengriMovementComponent(); + /** Get interpolated render location */ + UFUNCTION(BlueprintPure, Category = "Tengri Movement") + FVector GetRenderLocation() const { return RenderLocation; } + /** Event triggered when character lands (broadcast after physics loop completes) */ UPROPERTY(BlueprintAssignable, Category = "Tengri Movement|Events") FOnTengriLandingSignature OnLanded;