#include "SpaceshipPawn.h" #include "GameFramework/SpringArmComponent.h" #include "Camera/CameraComponent.h" #include "Components/StaticMeshComponent.h" #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" #include "SpaceshipProjectile.h" #include "Kismet/GameplayStatics.h" #include "GameFramework/GameUserSettings.h" ASpaceshipPawn::ASpaceshipPawn() { PrimaryActorTick.bCanEverTick = true; // Create ship mesh ShipMesh = CreateDefaultSubobject(TEXT("ShipMesh")); RootComponent = ShipMesh; ShipMesh->SetSimulatePhysics(false); ShipMesh->SetEnableGravity(false); // Create camera spring arm CameraSpringArm = CreateDefaultSubobject(TEXT("CameraSpringArm")); CameraSpringArm->SetupAttachment(RootComponent); CameraSpringArm->TargetArmLength = 400.0f; CameraSpringArm->bEnableCameraLag = true; CameraSpringArm->CameraLagSpeed = 10.0f; 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 // Create camera Camera = CreateDefaultSubobject(TEXT("Camera")); Camera->SetupAttachment(CameraSpringArm, USpringArmComponent::SocketName); // Initialize movement variables CurrentThrust = 0.0f; TargetThrust = 0.0f; bThrottlePressed = false; CurrentVelocity = FVector::ZeroVector; CurrentPitch = 0.0f; CurrentYaw = 0.0f; TargetRotation = FRotator::ZeroRotator; LastMouseDelta = FVector2D::ZeroVector; } void ASpaceshipPawn::BeginPlay() { Super::BeginPlay(); // Store player controller reference PlayerControllerRef = Cast(Controller); if (PlayerControllerRef) { // Setup input mapping context if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem(PlayerControllerRef->GetLocalPlayer())) { Subsystem->AddMappingContext(DefaultMappingContext, 0); } // Setup mouse capture and fullscreen PlayerControllerRef->SetShowMouseCursor(false); PlayerControllerRef->SetInputMode(FInputModeGameOnly()); // Request fullscreen mode using GameUserSettings UGameUserSettings* GameUserSettings = UGameUserSettings::GetGameUserSettings(); if (GameUserSettings) { GameUserSettings->SetFullscreenMode(EWindowMode::Fullscreen); GameUserSettings->SetScreenResolution(FIntPoint(1920, 1080)); // Adjust the resolution if needed GameUserSettings->ApplySettings(false); } } } void ASpaceshipPawn::Tick(float DeltaTime) { Super::Tick(DeltaTime); // Handle thrust if (!bThrottlePressed) { CurrentThrust = FMath::FInterpTo(CurrentThrust, 0.0f, DeltaTime, ThrustDeceleration); } else { CurrentThrust = FMath::FInterpTo(CurrentThrust, TargetThrust, DeltaTime, ThrustAcceleration); } // Update movement based on ship's forward vector FVector ThrustDirection = GetActorForwardVector(); FVector ThrustForce = ThrustDirection * CurrentThrust; // Apply drag FVector DragForce = -CurrentVelocity * DragCoefficient; // Update velocity CurrentVelocity += (ThrustForce + DragForce) * DeltaTime; // Update position FVector NewLocation = GetActorLocation() + (CurrentVelocity * DeltaTime); SetActorLocation(NewLocation, true); // Debug info if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Yellow, FString::Printf(TEXT("Thrust: %.2f"), CurrentThrust)); GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Green, FString::Printf(TEXT("Velocity: %.2f"), CurrentVelocity.Size())); } // Smooth mouse movement MouseDeltaSmoothed = FMath::Vector2DInterpTo( MouseDeltaSmoothed, LastMouseDelta, DeltaTime, MouseSmoothingSpeed ); // Update rotation based on smoothed mouse movement CurrentYaw += MouseDeltaSmoothed.X * MouseSensitivity * DeltaTime * 60.0f; // Multiply by 60 to normalize for frame rate CurrentPitch = FMath::ClampAngle( CurrentPitch + (MouseDeltaSmoothed.Y * MouseSensitivity * DeltaTime * 60.0f), -85.0f, 85.0f ); // Set target rotation TargetRotation = FRotator(CurrentPitch, CurrentYaw, 0.0f); // Smoothly interpolate to target rotation using quaternions for better interpolation FQuat CurrentQuat = GetActorQuat(); FQuat TargetQuat = TargetRotation.Quaternion(); FQuat NewQuat = FQuat::Slerp(CurrentQuat, TargetQuat, RotationSpeed * DeltaTime); SetActorRotation(NewQuat); // Update spring arm rotation to match ship with smooth interpolation if (CameraSpringArm) { FRotator SpringArmRotation = CameraSpringArm->GetComponentRotation(); FRotator TargetSpringArmRotation = NewQuat.Rotator(); FRotator NewSpringArmRotation = FMath::RInterpTo( SpringArmRotation, TargetSpringArmRotation, DeltaTime, RotationSpeed ); CameraSpringArm->SetWorldRotation(NewSpringArmRotation); } // Reset mouse delta for next frame LastMouseDelta = FVector2D::ZeroVector; // Debug info if (GEngine) { 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)); } } void ASpaceshipPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); if (UEnhancedInputComponent* EnhancedInputComponent = CastChecked(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 mouse control EnhancedInputComponent->BindAction(MouseLookAction, ETriggerEvent::Triggered, this, &ASpaceshipPawn::HandleMouseLook); // Bind fire action EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Triggered, this, &ASpaceshipPawn::HandleFire); } } // Split the throttle handling into two functions void ASpaceshipPawn::HandleThrottleStarted(const FInputActionValue& Value) { const float ThrottleValue = Value.Get(); bThrottlePressed = true; TargetThrust = ThrottleValue * MaxThrust; } void ASpaceshipPawn::HandleThrottleReleased(const FInputActionValue& Value) { bThrottlePressed = false; } void ASpaceshipPawn::HandleMouseLook(const FInputActionValue& Value) { const FVector2D MouseDelta = Value.Get(); // Smoothly interpolate mouse delta LastMouseDelta = MouseDelta; } void ASpaceshipPawn::HandleFire(const FInputActionValue& Value) { UWorld* World = GetWorld(); if (World) { FVector SpawnLocation = ShipMesh->GetSocketLocation(TEXT("ProjectileSpawn")); if (SpawnLocation == FVector::ZeroVector) { SpawnLocation = GetActorLocation() + (GetActorForwardVector() * 100.0f); } FRotator SpawnRotation = GetActorRotation(); FActorSpawnParameters SpawnParams; SpawnParams.Owner = this; SpawnParams.Instigator = GetInstigator(); World->SpawnActor( ASpaceshipProjectile::StaticClass(), SpawnLocation, SpawnRotation, SpawnParams ); } }