feat(movement): improve air control and ground snapping behavior
- Add directional air control modifier to prevent instant braking mid-air * Reduce control effectiveness by 50% when reversing direction (Dot < 0) * Allows side-to-side adjustments while maintaining forward momentum - Remove input requirement for velocity projection on ground snap * Project velocity onto slope even without player input * Preserves momentum when landing on slopes - Add KINDA_SMALL_NUMBER checks to prevent division by zero - Add GetRenderLocation() Blueprint accessor for VFX positioning - Clean up comments: translate Russian text to English This makes air movement feel more realistic (less like flying) while improving slope handling consistency.main
parent
abe8f565b6
commit
14d3696805
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue