173 lines
5.9 KiB
C++
173 lines
5.9 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"
|
|
|
|
ASpaceshipPawn::ASpaceshipPawn()
|
|
{
|
|
PrimaryActorTick.bCanEverTick = true;
|
|
|
|
// Create ship mesh
|
|
ShipMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("ShipMesh"));
|
|
RootComponent = ShipMesh;
|
|
ShipMesh->SetSimulatePhysics(false);
|
|
ShipMesh->SetEnableGravity(false);
|
|
|
|
// Create camera spring arm
|
|
CameraSpringArm = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraSpringArm"));
|
|
CameraSpringArm->SetupAttachment(RootComponent);
|
|
CameraSpringArm->TargetArmLength = 400.0f;
|
|
CameraSpringArm->bEnableCameraLag = true;
|
|
CameraSpringArm->CameraLagSpeed = 3.0f;
|
|
CameraSpringArm->bEnableCameraRotationLag = true;
|
|
CameraSpringArm->CameraRotationLagSpeed = 10.0f;
|
|
|
|
// 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;
|
|
CurrentRotation = GetActorQuat();
|
|
TargetRotation = GetActorRotation();
|
|
}
|
|
|
|
void ASpaceshipPawn::BeginPlay()
|
|
{
|
|
Super::BeginPlay();
|
|
|
|
// Add Input Mapping Context
|
|
if (APlayerController* PlayerController = Cast<APlayerController>(Controller))
|
|
{
|
|
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
|
|
{
|
|
Subsystem->AddMappingContext(DefaultMappingContext, 0);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ASpaceshipPawn::Tick(float DeltaTime)
|
|
{
|
|
Super::Tick(DeltaTime);
|
|
|
|
// Handle thrust deceleration when not pressing throttle
|
|
if (!bThrottlePressed)
|
|
{
|
|
CurrentThrust = FMath::FInterpTo(CurrentThrust, 0.0f, DeltaTime, ThrustDeceleration);
|
|
}
|
|
else
|
|
{
|
|
CurrentThrust = FMath::FInterpTo(CurrentThrust, TargetThrust, DeltaTime, ThrustAcceleration);
|
|
}
|
|
|
|
// Calculate movement
|
|
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);
|
|
|
|
// Smooth rotation using quaternion interpolation
|
|
FQuat TargetQuat = TargetRotation.Quaternion();
|
|
CurrentRotation = FQuat::Slerp(CurrentRotation, TargetQuat, RotationSpeed * DeltaTime);
|
|
SetActorRotation(CurrentRotation);
|
|
|
|
// 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<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(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<float>();
|
|
bThrottlePressed = true;
|
|
TargetThrust = ThrottleValue * MaxThrust;
|
|
}
|
|
|
|
void ASpaceshipPawn::HandleThrottleReleased(const FInputActionValue& Value)
|
|
{
|
|
bThrottlePressed = false;
|
|
}
|
|
|
|
void ASpaceshipPawn::HandleMouseControl(const FInputActionValue& Value)
|
|
{
|
|
const FVector2D MouseValue = Value.Get<FVector2D>();
|
|
|
|
// Get current rotation
|
|
FRotator CurrentRot = GetActorRotation();
|
|
|
|
// Calculate new rotation values
|
|
float NewPitch = CurrentRot.Pitch + (-MouseValue.Y * RotationSpeed * GetWorld()->GetDeltaSeconds());
|
|
float NewYaw = CurrentRot.Yaw + (MouseValue.X * RotationSpeed * GetWorld()->GetDeltaSeconds());
|
|
|
|
// Clamp pitch to prevent flipping
|
|
NewPitch = FMath::ClampAngle(NewPitch, -85.0f, 85.0f);
|
|
|
|
// Set target rotation
|
|
TargetRotation = FRotator(NewPitch, NewYaw, CurrentRot.Roll);
|
|
|
|
// Update camera spring arm rotation to match
|
|
CameraSpringArm->SetRelativeRotation(FRotator(NewPitch * 0.3f, 0.0f, 0.0f));
|
|
}
|
|
|
|
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>(
|
|
ASpaceshipProjectile::StaticClass(),
|
|
SpawnLocation,
|
|
SpawnRotation,
|
|
SpawnParams
|
|
);
|
|
}
|
|
} |