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

@@ -32,19 +32,19 @@ ASpaceshipPawn::ASpaceshipPawn()
CameraSpringArm->CameraLagSpeed = 10.0f; CameraSpringArm->CameraLagSpeed = 10.0f;
CameraSpringArm->bEnableCameraRotationLag = true; CameraSpringArm->bEnableCameraRotationLag = true;
CameraSpringArm->CameraRotationLagSpeed = 10.0f; CameraSpringArm->CameraRotationLagSpeed = 10.0f;
CameraSpringArm->CameraLagMaxDistance = 7.0f; CameraSpringArm->CameraLagMaxDistance = 7.0f;
CameraSpringArm->bUsePawnControlRotation = false; // Add this line CameraSpringArm->bUsePawnControlRotation = false;
CameraSpringArm->bInheritPitch = true; // Add this line CameraSpringArm->bInheritPitch = true;
CameraSpringArm->bInheritYaw = true; // Add this line CameraSpringArm->bInheritYaw = true;
CameraSpringArm->bInheritRoll = false; // Add this line CameraSpringArm->bInheritRoll = false;
// Create camera // Create camera
Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera")); Camera = CreateDefaultSubobject<UCameraComponent>(TEXT("Camera"));
Camera->SetupAttachment(CameraSpringArm, USpringArmComponent::SocketName); Camera->SetupAttachment(CameraSpringArm, USpringArmComponent::SocketName);
// Initialize movement variables // Initialize movement variables
CurrentThrust = 0.0f; CurrentThrottleInput = 0.0f;
TargetThrust = 0.0f; CurrentStrafeInput = 0.0f;
bThrottlePressed = false; bThrottlePressed = false;
CurrentVelocity = FVector::ZeroVector; CurrentVelocity = FVector::ZeroVector;
CurrentPitch = 0.0f; CurrentPitch = 0.0f;
@@ -110,15 +110,49 @@ void ASpaceshipPawn::Tick(float DeltaTime)
{ {
Super::Tick(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 // Debug info
if (GEngine) if (GEngine)
{ {
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Yellow, GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Yellow,
FString::Printf(TEXT("Thrust: %.2f"), CurrentThrust)); FString::Printf(TEXT("Mode: %s | Speed: %.1f"),
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Green, MovementMode == EShipMovementMode::Arcade ? TEXT("Arcade") :
FString::Printf(TEXT("Velocity: %.2f"), CurrentVelocity.Size())); MovementMode == EShipMovementMode::Assisted ? TEXT("Assisted") : TEXT("Realistic"),
} CurrentVelocity.Size()));
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Green,
FString::Printf(TEXT("Throttle: %.2f | Strafe: %.2f"),
CurrentThrottleInput, CurrentStrafeInput));
}
}
void ASpaceshipPawn::UpdateShipRotation(float DeltaTime)
{
// Smooth mouse movement // Smooth mouse movement
MouseDeltaSmoothed = FMath::Vector2DInterpTo( MouseDeltaSmoothed = FMath::Vector2DInterpTo(
MouseDeltaSmoothed, MouseDeltaSmoothed,
@@ -128,7 +162,7 @@ void ASpaceshipPawn::Tick(float DeltaTime)
); );
// Update rotation based on smoothed mouse movement // 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 = FMath::ClampAngle(
CurrentPitch + (MouseDeltaSmoothed.Y * MouseSensitivity * DeltaTime * 60.0f), CurrentPitch + (MouseDeltaSmoothed.Y * MouseSensitivity * DeltaTime * 60.0f),
-85.0f, -85.0f,
@@ -144,67 +178,6 @@ void ASpaceshipPawn::Tick(float DeltaTime)
FQuat NewQuat = FQuat::Slerp(CurrentQuat, TargetQuat, RotationSpeed * DeltaTime); FQuat NewQuat = FQuat::Slerp(CurrentQuat, TargetQuat, RotationSpeed * DeltaTime);
SetActorRotation(NewQuat); 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 // Update spring arm rotation to match ship with smooth interpolation
if (CameraSpringArm) if (CameraSpringArm)
{ {
@@ -218,17 +191,106 @@ void ASpaceshipPawn::Tick(float DeltaTime)
); );
CameraSpringArm->SetWorldRotation(NewSpringArmRotation); CameraSpringArm->SetWorldRotation(NewSpringArmRotation);
} }
}
// Reset mouse delta for next frame void ASpaceshipPawn::UpdateArcadeMovement(float DeltaTime)
LastMouseDelta = FVector2D::ZeroVector; {
// In arcade mode, the ship moves exactly where it's pointed with minimal inertia
FVector ForwardVector = GetActorForwardVector();
FVector RightVector = GetActorRightVector();
// Debug info // Calculate desired velocity (forward/back + strafe)
if (GEngine) 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))
{ {
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Yellow, // Accelerating
FString::Printf(TEXT("Smoothed Mouse Delta: X=%.2f Y=%.2f"), MouseDeltaSmoothed.X, MouseDeltaSmoothed.Y)); CurrentVelocity = FMath::VInterpTo(
GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Green, CurrentVelocity,
FString::Printf(TEXT("Current Rotation: P=%.2f Y=%.2f"), CurrentPitch, CurrentYaw)); 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)) if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(PlayerInputComponent))
{ {
// Bind both Hold and Released events for throttle // Bind throttle input
EnhancedInputComponent->BindAction(ThrottleAction, ETriggerEvent::Started, this, &ASpaceshipPawn::HandleThrottleStarted); EnhancedInputComponent->BindAction(ThrottleAction, ETriggerEvent::Triggered, this, &ASpaceshipPawn::HandleThrottleInput);
EnhancedInputComponent->BindAction(ThrottleAction, ETriggerEvent::Completed, this, &ASpaceshipPawn::HandleThrottleReleased);
// Bind strafe input if available
if (StrafeAction)
{
EnhancedInputComponent->BindAction(StrafeAction, ETriggerEvent::Triggered, this, &ASpaceshipPawn::HandleStrafeInput);
}
// Bind mouse control // Bind mouse control
EnhancedInputComponent->BindAction(MouseLookAction, ETriggerEvent::Triggered, this, &ASpaceshipPawn::HandleMouseLook); 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::HandleThrottleInput(const FInputActionValue& Value)
void ASpaceshipPawn::HandleThrottleStarted(const FInputActionValue& Value)
{ {
const float ThrottleValue = Value.Get<float>(); CurrentThrottleInput = Value.Get<float>();
bThrottlePressed = true; bThrottlePressed = !FMath::IsNearlyZero(CurrentThrottleInput);
TargetThrust = ThrottleValue * MaxThrust;
} }
void ASpaceshipPawn::HandleThrottleReleased(const FInputActionValue& Value) void ASpaceshipPawn::HandleStrafeInput(const FInputActionValue& Value)
{ {
bThrottlePressed = false; CurrentStrafeInput = Value.Get<float>();
} }
void ASpaceshipPawn::HandleMouseLook(const FInputActionValue& Value) void ASpaceshipPawn::HandleMouseLook(const FInputActionValue& Value)
{ {
const FVector2D MouseDelta = Value.Get<FVector2D>(); const FVector2D MouseDelta = Value.Get<FVector2D>();
// Smoothly interpolate mouse delta
LastMouseDelta = MouseDelta; LastMouseDelta = MouseDelta;
} }

View File

@@ -6,6 +6,15 @@
#include "Blueprint/UserWidget.h" #include "Blueprint/UserWidget.h"
#include "SpaceshipPawn.generated.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() UCLASS()
class MYPROJECT3_API ASpaceshipPawn : public APawn class MYPROJECT3_API ASpaceshipPawn : public APawn
{ {
@@ -41,29 +50,45 @@ protected:
// Movement Parameters // Movement Parameters
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement") UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float MaxThrust = 2000.0f; EShipMovementMode MovementMode = EShipMovementMode::Arcade;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement") UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float ThrustAcceleration = 500.0f; float MaxSpeed = 2000.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement") UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float ThrustDeceleration = 500.0f; float Acceleration = 2000.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement") 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") UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement")
float MouseSensitivity = 2.0f; float MouseSensitivity = 2.0f;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement") // Auto-stabilization for assisted mode
float DragCoefficient = 0.05f; 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")) UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Movement", meta = (ClampMin = "0.0", ClampMax = "10.0"))
float VelocityAlignmentSpeed = 4.0f; 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)")) // Auto-braking when not thrusting in Arcade mode
float DirectionalInertia = 0.3f; 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 // Shooting properties
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Combat") UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Combat")
@@ -86,14 +111,14 @@ protected:
UUserWidget* CrosshairWidget; UUserWidget* CrosshairWidget;
// Input functions // Input functions
void HandleThrottleStarted(const FInputActionValue& Value); void HandleThrottleInput(const FInputActionValue& Value);
void HandleThrottleReleased(const FInputActionValue& Value); void HandleStrafeInput(const FInputActionValue& Value);
void HandleMouseLook(const FInputActionValue& Value); void HandleMouseLook(const FInputActionValue& Value);
private: private:
// Movement state // Movement state
float CurrentThrust; float CurrentThrottleInput;
float TargetThrust; float CurrentStrafeInput;
bool bThrottlePressed; bool bThrottlePressed;
FVector CurrentVelocity; FVector CurrentVelocity;
FRotator TargetRotation; FRotator TargetRotation;
@@ -104,10 +129,7 @@ private:
FVector2D MouseDeltaSmoothed; FVector2D MouseDeltaSmoothed;
FVector2D LastMouseDelta; FVector2D LastMouseDelta;
float MouseSmoothingSpeed = 10.0f; float MouseSmoothingSpeed = 10.0f;
bool bWasThrottlePressed;
FVector DesiredVelocityDirection;
FTimerHandle FireTimerHandle; FTimerHandle FireTimerHandle;
bool bCanFire = true; bool bCanFire = true;
@@ -115,4 +137,10 @@ private:
void HandleShoot(const FInputActionValue& Value); void HandleShoot(const FInputActionValue& Value);
void Fire(); void Fire();
void ResetFire(); void ResetFire();
// Movement helper functions
void UpdateArcadeMovement(float DeltaTime);
void UpdateAssistedMovement(float DeltaTime);
void UpdateRealisticMovement(float DeltaTime);
void UpdateShipRotation(float DeltaTime);
}; };