#include "SpaceshipPawn.h" #include "GameFramework/SpringArmComponent.h" #include "Camera/CameraComponent.h" #include "Components/StaticMeshComponent.h" #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" #include "SpaceshipProjectile.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 = 3.0f; CameraSpringArm->bEnableCameraRotationLag = true; CameraSpringArm->CameraRotationLagSpeed = 10.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; ShipRotation = FRotator::ZeroRotator; } void ASpaceshipPawn::BeginPlay() { Super::BeginPlay(); // Add Input Mapping Context if (APlayerController* PlayerController = Cast(Controller)) { if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem(PlayerController->GetLocalPlayer())) { Subsystem->AddMappingContext(DefaultMappingContext, 0); } } } 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); } // Smoothly interpolate to target rotation FRotator CurrentRotation = GetActorRotation(); FRotator NewRotation = FMath::RInterpTo( CurrentRotation, ShipRotation, DeltaTime, RotationSpeed ); SetActorRotation(NewRotation); // 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())); } } 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(MouseControlAction, ETriggerEvent::Started, this, &ASpaceshipPawn::HandleMouseControl); // 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::HandleMouseControl(const FInputActionValue& Value) { const FVector2D MouseValue = Value.Get(); // Mouse sensitivity factors const float MouseSensitivityX = 1.0f; const float MouseSensitivityY = 1.0f; // Update current rotation based on mouse input CurrentYaw += MouseValue.X * MouseSensitivityX; CurrentPitch = FMath::ClampAngle(CurrentPitch + (-MouseValue.Y * MouseSensitivityY), -85.0f, 85.0f); // Create target rotation ShipRotation = FRotator(CurrentPitch, CurrentYaw, 0.0f); if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Blue, FString::Printf(TEXT("Mouse Input - X: %.2f, Y: %.2f"), MouseValue.X, MouseValue.Y)); GEngine->AddOnScreenDebugMessage(-1, 0.0f, FColor::Purple, FString::Printf(TEXT("Ship Rotation - Pitch: %.2f, Yaw: %.2f"), CurrentPitch, CurrentYaw)); } } 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 ); } }