ExoWest/Source/Exo/Private/Player/ExoPlayerController.cpp

512 lines
15 KiB
C++
Raw Normal View History

// Fill out your copyright notice in the Description page of Project Settings.
#include "Player/ExoPlayerController.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
#include "Characters/ExoPlayerCharacter.h"
#include "Components/CapsuleComponent.h"
#include "GameFramework/Character.h"
#include "GameFramework/CharacterMovementComponent.h"
AExoPlayerController::AExoPlayerController()
{
PrimaryActorTick.bCanEverTick = true;
}
void AExoPlayerController::BeginPlay()
{
Super::BeginPlay();
check(InputContext);
PlayerCharacter = Cast<AExoPlayerCharacter>(GetPawn<ACharacter>());
check(PlayerCharacter);
UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(GetLocalPlayer());
if (Subsystem)
{
Subsystem->AddMappingContext(InputContext, 0);
}
InteractionComponent = PlayerCharacter->InteractionComponent;
ShootingComponent = PlayerCharacter->ShootingComponent;
// Ustawianie w komponencie poruszania pr<70>dko<6B>ci zapisanej w characterze
PlayerCharacter->GetCharacterMovement()->MaxWalkSpeed = PlayerCharacter->WalkSpeed;
}
void AExoPlayerController::PlayerTick(float DeltaTime)
{
Super::PlayerTick(DeltaTime);
if (PlayerCharacter->bIsInCover)
{
//PlayerCharacter->SetEyePositionOffsetTarget(
// FVector(0, 0, PlayerCharacter->LowEyeHeightOffset)
// );
if (PlayerCharacter->bIsAimingMode)
{
CoverAimHeightOffset = CalculateCoverAimOffset();
PlayerCharacter->SetEyePositionOffsetTarget(
FVector(0.f, 0.f, CoverAimHeightOffset));
}
}
//else
//{
// PlayerCharacter->SetEyePositionOffsetTarget(FVector::ZeroVector);
//}
// On screen cover state DEBUG
if (bShowCoverSystemDebug)
{
GEngine->AddOnScreenDebugMessage(2, -1, FColor::Red,
FString::Printf(TEXT("In cover: %hs"),
PlayerCharacter->bIsInCover ? "true" : "false")
);
}
}
void AExoPlayerController::SetupInputComponent()
{
Super::SetupInputComponent();
UEnhancedInputComponent* EnhancedInputComponent = CastChecked<UEnhancedInputComponent>(InputComponent);
EnhancedInputComponent->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AExoPlayerController::Move);
EnhancedInputComponent->BindAction(LookAction, ETriggerEvent::Triggered, this, &AExoPlayerController::Look);
EnhancedInputComponent->BindAction(InteractAction, ETriggerEvent::Triggered, this, &AExoPlayerController::Interact);
EnhancedInputComponent->BindAction(JumpAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerJump);
EnhancedInputComponent->BindAction(DodgeAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerDodge);
EnhancedInputComponent->BindAction(CrouchAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerStartCrouch);
EnhancedInputComponent->BindAction(CrouchAction, ETriggerEvent::Completed, this, &AExoPlayerController::PlayerStopCrouch);
EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerStartSprint);
EnhancedInputComponent->BindAction(SprintAction, ETriggerEvent::Completed, this, &AExoPlayerController::PlayerStopSprint);
EnhancedInputComponent->BindAction(ShootAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerShoot);
EnhancedInputComponent->BindAction(ThrowAction, ETriggerEvent::Completed, this, &AExoPlayerController::PlayerThrow);
EnhancedInputComponent->BindAction(AimAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerStartAim);
EnhancedInputComponent->BindAction(AimAction, ETriggerEvent::Completed, this, &AExoPlayerController::PlayerStopAim);
EnhancedInputComponent->BindAction(MeleAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerMeleAttack);
EnhancedInputComponent->BindAction(ChangeWeaponAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerChangeWeapon);
2025-03-23 21:47:10 +01:00
EnhancedInputComponent->BindAction(SelectFirstWeaponAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerSelectFirstWeapon);
EnhancedInputComponent->BindAction(SelectSecondWeaponAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerSelectSecondWeapon);
EnhancedInputComponent->BindAction(DropWeaponAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerDropWeapon);
EnhancedInputComponent->BindAction(ReloadAction, ETriggerEvent::Started, this, &AExoPlayerController::PlayerReload);
}
void AExoPlayerController::Move(const FInputActionValue& InputActionValue)
{
const FVector2D InputAxisVector = InputActionValue.Get<FVector2D>();
const FRotator Rotation = GetControlRotation();
const FRotator YawRotation(0.f, Rotation.Yaw, 0.f);
const FVector ForwardDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::X);
const FVector RightDirection = FRotationMatrix(YawRotation).GetUnitAxis(EAxis::Y);
if (PlayerCharacter)
{
PlayerCharacter->AddMovementInput(ForwardDirection, InputAxisVector.X);
PlayerCharacter->AddMovementInput(RightDirection, InputAxisVector.Y);
}
}
void AExoPlayerController::Look(const FInputActionValue& InputActionValue)
{
FVector2D InputAxisVector = InputActionValue.Get<FVector2D>();
AddYawInput(InputAxisVector.X);
AddPitchInput(InputAxisVector.Y);
}
void AExoPlayerController::Interact()
{
if (InteractionComponent->InteractedActor)
IInteractable::Execute_Interact(InteractionComponent->InteractedActor, PlayerCharacter);
}
void AExoPlayerController::PlayerJump()
{
PlayerCharacter->Jump();
}
void AExoPlayerController::PlayerDodge()
{
UE_LOG(LogTemp, Error, TEXT("Player Dodge"));
if (PlayerCharacter->GetCharacterMovement()->IsFalling()) return;
if (PlayerCharacter->GetCharacterMovement()->IsCrouching()) return;
if (!CanDodge) return;
CanDodge = false;
FVector DodgeDirection = PlayerCharacter->GetVelocity().GetSafeNormal();
DodgeDirection.Z = 0.f;
if (DodgeDirection.IsNearlyZero())
DodgeDirection = PlayerCharacter->GetActorForwardVector();
PlayerCharacter->LaunchCharacter(DodgeDirection * PlayerCharacter->DodgeForce, true, true);
GetWorldTimerManager().SetTimer(DodgeCooldownTimer, this, &AExoPlayerController::ResetDodge, PlayerCharacter->DodgeCooldown, false);
}
void AExoPlayerController::ResetDodge()
{
CanDodge = true;
}
void AExoPlayerController::PlayerStartCrouch()
{
if (bIsSprinting)
{
PlayerCharacter->GetCharacterMovement()->MaxWalkSpeedCrouched = PlayerCharacter->SlideSpeed;
PlayerCharacter->SetTargetEyeHeight(PlayerCharacter->LowEyeHeightOffset);
GetWorldTimerManager().SetTimer(SlideCooldownTimer, this, &AExoPlayerController::ResetSlide, PlayerCharacter->SlideCooldown, false);
}
//PlayerCharacter->Crouch();
PlayerCharacter->CrouchCustom();
//PlayerCharacter->SetTargetEyeHeight(PlayerCharacter->CrouchedEyeHeight);
// PlayerCharacter->CameraComponent->SetRelativeLocation(FVector(
// 0.0f,
// 0.0f,
// PlayerCharacter->CrouchedEyeHeight)
// );
// Start checking for cover
PlayerCharacter->bIsInCover = CheckForCover();
GetWorld()->GetTimerManager().SetTimer(
CoverCheckTimer,
this,
&AExoPlayerController::OnCoverTimer,
CoverCheckRate,
true
);
}
void AExoPlayerController::PlayerStopCrouch()
{
//PlayerCharacter->UnCrouch();
PlayerCharacter->UnCrouchCustom();
//PlayerCharacter->SetTargetEyeHeight(PlayerCharacter->GetStandingEyeHeight());
// PlayerCharacter->CameraComponent->SetRelativeLocation(FVector(
// 0.0f,
// 0.0f,
// PlayerCharacter->BaseEyeHeight)
// );
// Stop checking for cover
GetWorld()->GetTimerManager().ClearTimer(CoverCheckTimer);
PlayerCharacter->bIsInCover = false;
TargetCoverStandAlpha = 0.0f;
}
void AExoPlayerController::ResetSlide()
{
PlayerCharacter->GetCharacterMovement()->MaxWalkSpeedCrouched = PlayerCharacter->CrouchSpeed;
PlayerCharacter->SetTargetEyeHeight(PlayerCharacter->CrouchedEyeHeight);
}
void AExoPlayerController::PlayerStartSprint()
{
if (!PlayerCharacter->bIsAimingMode)
{
UE_LOG(LogTemp, Display, TEXT("Start sprint"));
bIsSprinting = true;
PlayerCharacter->GetCharacterMovement()->MaxWalkSpeed = PlayerCharacter->SprintSpeed;
}
}
void AExoPlayerController::PlayerStopSprint()
{
if (!PlayerCharacter->bIsAimingMode)
{
UE_LOG(LogTemp, Display, TEXT("Stop sprint"));
bIsSprinting = false;
PlayerCharacter->GetCharacterMovement()->MaxWalkSpeed = PlayerCharacter->WalkSpeed;
}
}
void AExoPlayerController::PlayerShoot()
{
ShootingComponent->Shoot();
}
void AExoPlayerController::PlayerThrow()
{
ShootingComponent->Throw();
}
void AExoPlayerController::PlayerStartAim()
{
ShootingComponent->StartAiming();
}
void AExoPlayerController::PlayerStopAim()
{
ShootingComponent->StopAiming();
if (PlayerCharacter->bIsInCover)
{
CalculateCoverAimOffset();
}
}
void AExoPlayerController::PlayerMeleAttack()
{
ShootingComponent->MeleAttack();
}
void AExoPlayerController::PlayerChangeWeapon()
{
2025-03-23 21:47:10 +01:00
ShootingComponent->SwitchGun();
}
void AExoPlayerController::PlayerSelectFirstWeapon()
{
ShootingComponent->SelectGun(true);
}
void AExoPlayerController::PlayerSelectSecondWeapon()
{
ShootingComponent->SelectGun(false);
}
void AExoPlayerController::PlayerDropWeapon()
{
ShootingComponent->DropGun();
}
void AExoPlayerController::PlayerReload()
{
ShootingComponent->Reload();
}
bool AExoPlayerController::CheckForCover()
{
// Cover is recalculated every time the player crouches or stops moving while crouched
// Cover targets are cleared completely when player stands up again or dies
// Do a simple 8-directional line trace
FVector TraceDirection = PlayerCharacter->GetActorForwardVector();
FVector TraceStart = PlayerCharacter->GetActorLocation();
TraceStart.Z += bUseEyeHeight ?
PlayerCharacter->GetCrouchingEyeHeight(true)
:
PlayerCharacter->GetPlayerLocationAtFeet().Z + CoverObstacleMinHeight;
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(PlayerCharacter);
TArray<FHitResult> ValidHits;
for (int i = 0; i <= 8; i++)
{
// Trace for possible cover at set distance
FHitResult Hit;
FVector TraceEnd = TraceStart + (TraceDirection * MaxDistanceFromCover);
GetWorld()->LineTraceSingleByChannel(
Hit,
TraceStart,
TraceEnd,
CoverTraceChannel,
QueryParams
);
if (bShowCoverSystemDebug)
{
// DEBUG
DrawDebugLine(GetWorld(), TraceStart,TraceEnd,
Hit.bBlockingHit ? FColor::Blue : FColor::Red,
false, 5.0f, 0, 1.0f);
}
if (Hit.bBlockingHit == true) {
// Check if this particular hit isn't against a wall (>CoverMaxHeight)
FHitResult SphereHit;
FVector SpherePosition = Hit.ImpactPoint;
SpherePosition.Z = PlayerCharacter->GetPlayerLocationAtFeet().Z + CoverObstacleMaxHeight + CoverAimWindowRadius;
GetWorld()->SweepSingleByChannel(
SphereHit,
SpherePosition,
SpherePosition,
FQuat::Identity,
CoverTraceChannel,
FCollisionShape::MakeSphere(CoverAimWindowRadius),
QueryParams);
if (bShowCoverSystemDebug)
{
DrawDebugSphere(GetWorld(), SphereHit.TraceStart, CoverAimWindowRadius, 8,
Hit.bBlockingHit ? FColor::Blue : FColor::Red,
false, 5.0f, 0, 1);
}
if (SphereHit.bBlockingHit == false)
{
ValidHits.Add(Hit);
}
}
// Rotate trace to search in another direction next time
TraceDirection = TraceDirection.RotateAngleAxis(45, FVector(0, 0, 1));
//UE_LOG(LogTemp, Display, TEXT("Check Cover %d"), i);
}
return ValidHits.Num() > 0;
}
float AExoPlayerController::CalculateCoverAimOffset()
{
// Nic nie rób jak nie znajdujesz się za osłoną
if (!PlayerCharacter->bIsInCover)
{
return 0.f;
}
// Oblicz maksymalną wysokość na którą można wychylić się z nad osłony
MaxCoverAimHeightOffset = PlayerCharacter->GetStandingEyeHeight() * CoverAimStandFactor;
FVector ObstacleTraceStart = GetCharacter()->GetActorLocation();
ObstacleTraceStart.Z +=
bUseEyeHeight ?
PlayerCharacter->GetCurrentEyeHeight(true)
:
PlayerCharacter->CrouchedEyeHeight - GetCharacter()->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
FVector ObstacleTraceEnd =
ObstacleTraceStart + PlayerCameraManager->GetCameraRotation().Vector() * CoverAimFreeDistance;
FCollisionQueryParams QueryParams;
QueryParams.AddIgnoredActor(PlayerCharacter);
TEnumAsByte<ECollisionChannel> ObstacleTraceChannel = ECC_WorldStatic;
FHitResult Hit;
bool bFreeSpace = false;
// SphereTrace until no hit is found (free space to aim)
// for (int i = 0; i < MaxCoverAimHeight; i += CoverAimWindowRadius)
// {
// ObstacleTraceStart.Z += i;
// ObstacleTraceEnd.Z += i;
//
// GetWorld()->SweepSingleByChannel(
// Hit,
// ObstacleTraceStart,
// ObstacleTraceEnd,
// FQuat::Identity,
// ObstacleTraceChannel,
// FCollisionShape::MakeSphere(CoverAimWindowRadius),
// QueryParams
// );
//
// if (bShowCoverSystemDebug)
// {
// DrawDebugSphere(GetWorld(), Hit.Location, CoverAimWindowRadius, 8,
// Hit.bBlockingHit ? FColor::Blue : FColor::Red,
// false, 0.0f, 0, 0);
// }
//
// if (Hit.bBlockingHit == false)
// {
// UE_LOG(LogTemp, Display, TEXT("Free space"));
// bFreeSpace = true;
// break;
// }
// }
float SafeCoverAimZOffset = 0.f;
while (SafeCoverAimZOffset < MaxCoverAimHeightOffset)
{
ObstacleTraceStart.Z += SafeCoverAimZOffset;
ObstacleTraceEnd.Z += SafeCoverAimZOffset;
GetWorld()->SweepSingleByChannel(
Hit,
ObstacleTraceStart,
ObstacleTraceEnd,
FQuat::Identity,
ObstacleTraceChannel,
FCollisionShape::MakeSphere(CoverAimWindowRadius),
QueryParams
);
if (Hit.bBlockingHit == true)
{
// Increment check height every failed iteration
SafeCoverAimZOffset += 0.2f;
}
else
{
// Break the loop if free space found
break;
}
}
// If this is true that means that free space was found
if (SafeCoverAimZOffset <= MaxCoverAimHeightOffset)
{
//// DEBUG ////
if (bShowCoverSystemDebug)
{
DrawDebugLine(GetWorld(), Hit.TraceStart, Hit.TraceEnd, FColor::Purple);
}
//////////////
return SafeCoverAimZOffset;// +
//PlayerCharacter->CrouchedEyeHeight - PlayerCharacter->GetCurrentEyeHeight();
}
// Return 0 offset if no free space to aim was found
return 0.f;
}
void AExoPlayerController::UpdateSmoothCoverCamera(float DeltaTime)
{
if (FMath::IsNearlyEqual(CoverStandAlpha, TargetCoverStandAlpha, 0.01f))
{
return;
}
CoverStandAlpha = FMath::Lerp(CoverStandAlpha, TargetCoverStandAlpha, DeltaTime * 5.0f);
// BANDAID SOLUTION
const float NewZ = FMath::Lerp(
PlayerCharacter->GetCrouchingEyeHeight(),
PlayerCharacter->GetStandingEyeHeight(),
CoverStandAlpha
);
PlayerCharacter->CameraComponent->SetRelativeLocation(
FVector(0.0f, 0.0f, NewZ)
);
// DEBUG
if (bShowCoverSystemDebug && GEngine)
{
GEngine->AddOnScreenDebugMessage(1, -1, FColor::Red, FString::Printf(TEXT("Current cover stand alpha: %f"), CoverStandAlpha));
}
}
void AExoPlayerController::OnCoverTimer()
{
PlayerCharacter->bIsInCover = CheckForCover();
if (PlayerCharacter->bIsInCover == false)
{
TargetCoverStandAlpha = 0.0f;
UpdateSmoothCoverCamera(GetWorld()->GetDeltaSeconds());
}
}
void AExoPlayerController::DebugCoverSystem(bool show)
{
bShowCoverSystemDebug = show;
}