Files
Yamato/Source/MyProject3/SpaceshipPawn.cpp
2025-02-17 23:24:04 +05:30

338 lines
12 KiB
C++

#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<UStaticMeshComponent>(TEXT("ShipMesh"));
RootComponent = ShipMesh;
ShipMesh->SetSimulatePhysics(false);
ShipMesh->SetEnableGravity(false);
// Create projectile spawn point
ProjectileSpawnPoint = CreateDefaultSubobject<USceneComponent>(TEXT("ProjectileSpawnPoint"));
ProjectileSpawnPoint->SetupAttachment(ShipMesh);
// Create camera spring arm
CameraSpringArm = CreateDefaultSubobject<USpringArmComponent>(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<UCameraComponent>(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;
if (ShipMesh)
{
ShipMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
ShipMesh->SetCollisionObjectType(ECC_GameTraceChannel1); // This is the "Player" channel
ShipMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Block);
ShipMesh->SetCollisionResponseToChannel(ECC_GameTraceChannel1, ECollisionResponse::ECR_Ignore);
ShipMesh->SetCollisionResponseToChannel(ECC_Pawn, ECollisionResponse::ECR_Ignore);
}
}
void ASpaceshipPawn::BeginPlay()
{
Super::BeginPlay();
// Debug messages for setup verification
if (GEngine)
{
if (ProjectileClass)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("ProjectileClass is set"));
else
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("ProjectileClass is NOT set"));
if (ShootAction)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("ShootAction is set"));
else
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("ShootAction is NOT set"));
if (ProjectileSpawnPoint)
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Green, TEXT("ProjectileSpawnPoint is set"));
else
GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, TEXT("ProjectileSpawnPoint is NOT set"));
}
// Store player controller reference
PlayerControllerRef = Cast<APlayerController>(Controller);
if (PlayerControllerRef)
{
// Setup input mapping context
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(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);
// 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);
// 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)
{
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<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 mouse control
EnhancedInputComponent->BindAction(MouseLookAction, ETriggerEvent::Triggered, this, &ASpaceshipPawn::HandleMouseLook);
// Add shooting binding
EnhancedInputComponent->BindAction(ShootAction, ETriggerEvent::Triggered, this, &ASpaceshipPawn::HandleShoot);
}
}
// Split the throttle handling into two functions
void ASpaceshipPawn::HandleThrottleStarted(const FInputActionValue& Value)
{
const float ThrottleValue = Value.Get<float>();
bThrottlePressed = true;
TargetThrust = ThrottleValue * MaxThrust;
}
void ASpaceshipPawn::HandleThrottleReleased(const FInputActionValue& Value)
{
bThrottlePressed = false;
}
void ASpaceshipPawn::HandleMouseLook(const FInputActionValue& Value)
{
const FVector2D MouseDelta = Value.Get<FVector2D>();
// Smoothly interpolate mouse delta
LastMouseDelta = MouseDelta;
}
void ASpaceshipPawn::HandleShoot(const FInputActionValue& Value)
{
// Debug message
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Yellow, TEXT("HandleShoot Called"));
if (bCanFire)
{
Fire();
}
}
void ASpaceshipPawn::Fire()
{
// Debug messages
if (!ProjectileClass)
{
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Red, TEXT("ProjectileClass not set!"));
return;
}
UWorld* World = GetWorld();
if (World)
{
FVector SpawnLocation = ProjectileSpawnPoint->GetComponentLocation();
FRotator SpawnRotation = GetActorRotation();
FActorSpawnParameters SpawnParams;
SpawnParams.Owner = this;
SpawnParams.Instigator = GetInstigator();
// Spawn the projectile
ASpaceshipProjectile* Projectile = World->SpawnActor<ASpaceshipProjectile>(
ProjectileClass,
SpawnLocation,
SpawnRotation,
SpawnParams
);
if (Projectile)
{
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Green, TEXT("Projectile Spawned"));
}
else
{
if (GEngine)
GEngine->AddOnScreenDebugMessage(-1, 2.f, FColor::Red, TEXT("Failed to spawn projectile"));
}
// Start fire rate timer
bCanFire = false;
GetWorldTimerManager().SetTimer(FireTimerHandle, this, &ASpaceshipPawn::ResetFire, FireRate, false);
}
}
void ASpaceshipPawn::ResetFire()
{
bCanFire = true;
}