Modify movement implementation for more arcade feel and add strafing

This commit is contained in:
2025-04-15 14:51:25 +05:30
parent 0ba3948af3
commit ca23fd129e
9 changed files with 209 additions and 124 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
Content/Input/IA_Strafe.uasset LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -33,18 +33,18 @@ ASpaceshipPawn::ASpaceshipPawn()
CameraSpringArm->bEnableCameraRotationLag = true;
CameraSpringArm->CameraRotationLagSpeed = 10.0f;
CameraSpringArm->CameraLagMaxDistance = 7.0f;
CameraSpringArm->bUsePawnControlRotation = false; // Add this line
CameraSpringArm->bInheritPitch = true; // Add this line
CameraSpringArm->bInheritYaw = true; // Add this line
CameraSpringArm->bInheritRoll = false; // Add this line
CameraSpringArm->bUsePawnControlRotation = false;
CameraSpringArm->bInheritPitch = true;
CameraSpringArm->bInheritYaw = true;
CameraSpringArm->bInheritRoll = false;
// Create camera
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
Camera->SetupAttachment(CameraSpringArm, USpringArmComponent::SocketName);
// Initialize movement variables
CurrentThrust = 0.0f;
TargetThrust = 0.0f;
CurrentThrottleInput = 0.0f;
CurrentStrafeInput = 0.0f;
bThrottlePressed = false;
CurrentVelocity = FVector::ZeroVector;
CurrentPitch = 0.0f;
@@ -110,15 +110,49 @@ void ASpaceshipPawn::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
// Update ship rotation first (common to all movement modes)
UpdateShipRotation(DeltaTime);
// Handle movement based on the selected movement mode
switch (MovementMode)
{
case EShipMovementMode::Arcade:
UpdateArcadeMovement(DeltaTime);
break;
case EShipMovementMode::Assisted:
UpdateAssistedMovement(DeltaTime);
break;
case EShipMovementMode::Realistic:
UpdateRealisticMovement(DeltaTime);
break;
}
// Update position
FVector NewLocation = GetActorLocation() + (CurrentVelocity * DeltaTime);
SetActorLocation(NewLocation, true);
// Reset mouse delta for next frame
LastMouseDelta = FVector2D::ZeroVector;
// Debug info
if (GEngine)
{
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Yellow,
FString::Printf(TEXT("Thrust: %.2f"), CurrentThrust));
FString::Printf(TEXT("Mode: %s | Speed: %.1f"),
MovementMode == EShipMovementMode::Arcade ? TEXT("Arcade") :
MovementMode == EShipMovementMode::Assisted ? TEXT("Assisted") : TEXT("Realistic"),
CurrentVelocity.Size()));
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Green,
FString::Printf(TEXT("Velocity: %.2f"), CurrentVelocity.Size()));
FString::Printf(TEXT("Throttle: %.2f | Strafe: %.2f"),
CurrentThrottleInput, CurrentStrafeInput));
}
}
void ASpaceshipPawn::UpdateShipRotation(float DeltaTime)
{
// Smooth mouse movement
MouseDeltaSmoothed = FMath::Vector2DInterpTo(
MouseDeltaSmoothed,
@@ -128,7 +162,7 @@ void ASpaceshipPawn::Tick(float DeltaTime)
);
// Update rotation based on smoothed mouse movement
CurrentYaw += MouseDeltaSmoothed.X * MouseSensitivity * DeltaTime * 60.0f; // Multiply by 60 to normalize for frame rate
CurrentYaw += MouseDeltaSmoothed.X * MouseSensitivity * DeltaTime * 60.0f;
CurrentPitch = FMath::ClampAngle(
CurrentPitch + (MouseDeltaSmoothed.Y * MouseSensitivity * DeltaTime * 60.0f),
-85.0f,
@@ -144,67 +178,6 @@ void ASpaceshipPawn::Tick(float DeltaTime)
FQuat NewQuat = FQuat::Slerp(CurrentQuat, TargetQuat, RotationSpeed * DeltaTime);
SetActorRotation(NewQuat);
// Get the current forward vector
FVector CurrentDirection = GetActorForwardVector();
float CurrentSpeed = CurrentVelocity.Size();
// Handle thrust and velocity direction
if (!bThrottlePressed)
{
// Decelerate when not thrusting
CurrentThrust = FMath::FInterpTo(CurrentThrust, 0.0f, DeltaTime, ThrustDeceleration);
bWasThrottlePressed = false;
// Maintain current velocity direction when not thrusting
DesiredVelocityDirection = CurrentVelocity.GetSafeNormal();
}
else
{
// Accelerate when thrusting
CurrentThrust = FMath::FInterpConstantTo(CurrentThrust, TargetThrust, DeltaTime, ThrustAcceleration);
if (!bWasThrottlePressed)
{
// Just started thrusting - blend between current and new direction
if (!CurrentVelocity.IsNearlyZero())
{
// Blend between current velocity direction and new direction
FVector CurrentDir = CurrentVelocity.GetSafeNormal();
DesiredVelocityDirection = FMath::Lerp(CurrentDir, CurrentDirection, 1.0f - DirectionalInertia);
DesiredVelocityDirection.Normalize();
}
else
{
// If nearly stationary, use new direction
DesiredVelocityDirection = CurrentDirection;
}
}
else
{
// Continuously blend towards current facing direction while thrusting
DesiredVelocityDirection = FMath::VInterpNormalRotationTo(
DesiredVelocityDirection,
CurrentDirection,
DeltaTime,
VelocityAlignmentSpeed
);
}
bWasThrottlePressed = true;
}
// Calculate thrust force
FVector ThrustForce = CurrentDirection * CurrentThrust;
// Apply drag
FVector DragForce = -CurrentVelocity * DragCoefficient;
// Update velocity with forces
CurrentVelocity += (ThrustForce + DragForce) * DeltaTime;
// Update position
FVector NewLocation = GetActorLocation() + (CurrentVelocity * DeltaTime);
SetActorLocation(NewLocation, true);
// Update spring arm rotation to match ship with smooth interpolation
if (CameraSpringArm)
{
@@ -218,17 +191,106 @@ void ASpaceshipPawn::Tick(float DeltaTime)
);
CameraSpringArm->SetWorldRotation(NewSpringArmRotation);
}
}
// Reset mouse delta for next frame
LastMouseDelta = FVector2D::ZeroVector;
// Debug info
if (GEngine)
void ASpaceshipPawn::UpdateArcadeMovement(float DeltaTime)
{
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Yellow,
FString::Printf(TEXT("Smoothed Mouse Delta: X=%.2f Y=%.2f"), MouseDeltaSmoothed.X, MouseDeltaSmoothed.Y));
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Green,
FString::Printf(TEXT("Current Rotation: P=%.2f Y=%.2f"), CurrentPitch, CurrentYaw));
// In arcade mode, the ship moves exactly where it's pointed with minimal inertia
FVector ForwardVector = GetActorForwardVector();
FVector RightVector = GetActorRightVector();
// Calculate desired velocity (forward/back + strafe)
FVector DesiredVelocity = (ForwardVector * CurrentThrottleInput * MaxSpeed) +
(RightVector * CurrentStrafeInput * (MaxSpeed * 0.7f)); // Strafe is slightly slower
// Smoothly interpolate current velocity to desired velocity
if (!FMath::IsNearlyZero(CurrentThrottleInput) || !FMath::IsNearlyZero(CurrentStrafeInput))
{
// Accelerating
CurrentVelocity = FMath::VInterpTo(
CurrentVelocity,
DesiredVelocity,
DeltaTime,
Acceleration / MaxSpeed
);
}
else if (bAutoBrakeEnabled)
{
// Auto-braking when no input
CurrentVelocity = FMath::VInterpTo(
CurrentVelocity,
FVector::ZeroVector,
DeltaTime,
AutoBrakeStrength
);
}
else
{
// Gradual deceleration
float Speed = CurrentVelocity.Size();
if (Speed > 0)
{
Speed = FMath::FInterpTo(Speed, 0, DeltaTime, Deceleration / MaxSpeed);
CurrentVelocity = CurrentVelocity.GetSafeNormal() * Speed;
}
}
}
void ASpaceshipPawn::UpdateAssistedMovement(float DeltaTime)
{
// Assisted mode - a middle ground with some inertia but stabilization assistance
FVector ForwardVector = GetActorForwardVector();
FVector RightVector = GetActorRightVector();
// Calculate thrust force
FVector ThrustForce = (ForwardVector * CurrentThrottleInput * Acceleration) +
(RightVector * CurrentStrafeInput * (Acceleration * 0.7f));
// Apply thrust to velocity
CurrentVelocity += ThrustForce * DeltaTime;
// Limit max speed
float CurrentSpeed = CurrentVelocity.Size();
if (CurrentSpeed > MaxSpeed)
{
CurrentVelocity = CurrentVelocity.GetSafeNormal() * MaxSpeed;
}
// Apply auto-stabilization (gradual slowdown) when not thrusting
if (FMath::IsNearlyZero(CurrentThrottleInput) && FMath::IsNearlyZero(CurrentStrafeInput) && bAutoBrakeEnabled)
{
CurrentVelocity = FMath::VInterpTo(
CurrentVelocity,
FVector::ZeroVector,
DeltaTime,
StabilizationSpeed
);
}
}
void ASpaceshipPawn::UpdateRealisticMovement(float DeltaTime)
{
// This is the original physics-based movement with momentum
FVector CurrentDirection = GetActorForwardVector();
FVector RightVector = GetActorRightVector();
// Calculate thrust force (forward + strafe)
FVector ThrustForce = (CurrentDirection * CurrentThrottleInput * Acceleration) +
(RightVector * CurrentStrafeInput * (Acceleration * 0.7f));
// Apply thrust to velocity
CurrentVelocity += ThrustForce * DeltaTime;
// Apply drag
float DragCoefficient = 0.05f;
FVector DragForce = -CurrentVelocity * DragCoefficient;
CurrentVelocity += DragForce * DeltaTime;
// Limit max speed
float CurrentSpeed = CurrentVelocity.Size();
if (CurrentSpeed > MaxSpeed)
{
CurrentVelocity = CurrentVelocity.GetSafeNormal() * MaxSpeed;
}
}
@@ -238,9 +300,14 @@ void ASpaceshipPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputCompo
if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
{
// Bind both Hold and Released events for throttle
EnhancedInputComponent->BindAction(ThrottleAction, ETriggerEvent::Started, this, &ASpaceshipPawn::HandleThrottleStarted);
EnhancedInputComponent->BindAction(ThrottleAction, ETriggerEvent::Completed, this, &ASpaceshipPawn::HandleThrottleReleased);
// Bind throttle input
EnhancedInputComponent->BindAction(ThrottleAction, ETriggerEvent::Triggered, this, &ASpaceshipPawn::HandleThrottleInput);
// Bind strafe input if available
if (StrafeAction)
{
EnhancedInputComponent->BindAction(StrafeAction, ETriggerEvent::Triggered, this, &ASpaceshipPawn::HandleStrafeInput);
}
// Bind mouse control
EnhancedInputComponent->BindAction(MouseLookAction, ETriggerEvent::Triggered, this, &ASpaceshipPawn::HandleMouseLook);
@@ -250,24 +317,20 @@ void ASpaceshipPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputCompo
}
}
// Split the throttle handling into two functions
void ASpaceshipPawn::HandleThrottleStarted(const FInputActionValue& Value)
void ASpaceshipPawn::HandleThrottleInput(const FInputActionValue& Value)
{
const float ThrottleValue = Value.Get<float>();
bThrottlePressed = true;
TargetThrust = ThrottleValue * MaxThrust;
CurrentThrottleInput = Value.Get<float>();
bThrottlePressed = !FMath::IsNearlyZero(CurrentThrottleInput);
}
void ASpaceshipPawn::HandleThrottleReleased(const FInputActionValue& Value)
void ASpaceshipPawn::HandleStrafeInput(const FInputActionValue& Value)
{
bThrottlePressed = false;
CurrentStrafeInput = Value.Get<float>();
}
void ASpaceshipPawn::HandleMouseLook(const FInputActionValue& Value)
{
const FVector2D MouseDelta = Value.Get<FVector2D>();
// Smoothly interpolate mouse delta
LastMouseDelta = MouseDelta;
}

View File

@@ -6,6 +6,15 @@
#include "Blueprint/UserWidget.h"
#include "SpaceshipPawn.generated.h"
// Movement mode enum to allow switching between different control schemes
UENUM(BlueprintType)
enum class EShipMovementMode : uint8
{
Arcade, // Direct control, minimal inertia
Assisted, // Some inertia with auto-stabilization
Realistic // Full physics with momentum (original)
};
UCLASS()
class MYPROJECT3_API ASpaceshipPawn : public APawn
{
@@ -41,29 +50,45 @@ protected:
// Movement Parameters
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float MaxThrust = 2000.0f;
EShipMovementMode MovementMode = EShipMovementMode::Arcade;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float ThrustAcceleration = 500.0f;
float MaxSpeed = 2000.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float ThrustDeceleration = 500.0f;
float Acceleration = 2000.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float RotationSpeed = 100.0f;
float Deceleration = 1500.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float RotationSpeed = 5.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float MouseSensitivity = 2.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float DragCoefficient = 0.05f;
// Auto-stabilization for assisted mode
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement", meta = (ClampMin = "0.0", ClampMax = "10.0"))
float StabilizationSpeed = 3.0f;
// How quickly velocity aligns with new direction
// How much momentum to preserve when changing direction (0 = none, 1 = full)
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement", meta = (ClampMin = "0.0", ClampMax = "1.0"))
float DirectionalInertia = 0.1f;
// How quickly the ship aligns with its movement direction
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement", meta = (ClampMin = "0.0", ClampMax = "10.0"))
float VelocityAlignmentSpeed = 4.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement", meta = (ClampMin = "0.0", ClampMax = "1.0", ToolTip = "How much of the current velocity is maintained when changing direction (0 = none, 1 = full)"))
float DirectionalInertia = 0.3f;
// Auto-braking when not thrusting in Arcade mode
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
bool bAutoBrakeEnabled = true;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float AutoBrakeStrength = 3.0f;
// Add a strafe input to allow lateral movement
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input")
class UInputAction* StrafeAction;
// Shooting properties
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Combat")
@@ -86,14 +111,14 @@ protected:
UUserWidget* CrosshairWidget;
// Input functions
void HandleThrottleStarted(const FInputActionValue& Value);
void HandleThrottleReleased(const FInputActionValue& Value);
void HandleThrottleInput(const FInputActionValue& Value);
void HandleStrafeInput(const FInputActionValue& Value);
void HandleMouseLook(const FInputActionValue& Value);
private:
// Movement state
float CurrentThrust;
float TargetThrust;
float CurrentThrottleInput;
float CurrentStrafeInput;
bool bThrottlePressed;
FVector CurrentVelocity;
FRotator TargetRotation;
@@ -106,13 +131,16 @@ private:
FVector2D LastMouseDelta;
float MouseSmoothingSpeed = 10.0f;
bool bWasThrottlePressed;
FVector DesiredVelocityDirection;
FTimerHandle FireTimerHandle;
bool bCanFire = true;
void HandleShoot(const FInputActionValue& Value);
void Fire();
void ResetFire();
// Movement helper functions
void UpdateArcadeMovement(float DeltaTime);
void UpdateAssistedMovement(float DeltaTime);
void UpdateRealisticMovement(float DeltaTime);
void UpdateShipRotation(float DeltaTime);
};