309 lines
9.5 KiB
C++
309 lines
9.5 KiB
C++
// Fill out your copyright notice in the Description page of Project Settings.
|
||
|
||
|
||
#include "Characters/Components/ShootingComponent.h"
|
||
|
||
#include "Items/ThrowableBase.h"
|
||
|
||
// Sets default values for this component's properties
|
||
UShootingComponent::UShootingComponent()
|
||
{
|
||
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
|
||
// off to improve performance if you don't need them.
|
||
PrimaryComponentTick.bCanEverTick = true;
|
||
|
||
// ...
|
||
}
|
||
|
||
|
||
// Called when the game starts
|
||
void UShootingComponent::BeginPlay()
|
||
{
|
||
Super::BeginPlay();
|
||
|
||
PlayerCharacter = Cast<AExoPlayerCharacter>(GetOwner());
|
||
CameraManager = GetWorld()->GetFirstPlayerController()->PlayerCameraManager;
|
||
|
||
DefaultFOV = CameraManager->GetFOVAngle();
|
||
TargetFOV = DefaultFOV;
|
||
}
|
||
|
||
void UShootingComponent::Shoot()
|
||
{
|
||
if (!IsValid(CurrentGun) || CurrentGun->CurrentAmmo == 0 || bIsReloading || !bCanShoot) return;
|
||
|
||
bCanShoot = false;
|
||
CurrentGun->CurrentAmmo--;
|
||
|
||
AActor* HitActor = ExecuteLineTrace(CurrentGun->MaxRange);
|
||
if (HitActor)
|
||
{
|
||
IDamageable::Execute_TakeDamage(HitActor, CurrentGun->DamageValue);
|
||
|
||
UE_LOG(LogTemp, Display, TEXT("Shoot. Ammo: %d/%d"), CurrentGun->CurrentAmmo, CurrentGun->MaxAmmo); // Docelowo tutaj wywołanie UI aktualizujące stan ammo
|
||
}
|
||
|
||
PlayerCharacter->GetWorldTimerManager().SetTimer(ShootCooldownTimer, this, &UShootingComponent::ResetFireCooldown, CurrentGun->FireRateCooldown, false);
|
||
|
||
// Odrzut
|
||
float RecoilPitch = FMath::RandRange(-1.0f, -0.5f);
|
||
float RecoilYaw = FMath::RandRange(-0.5f, 0.5f);
|
||
|
||
PlayerCharacter->AddControllerPitchInput(RecoilPitch * CurrentGun->RecoilForceMultiplier);
|
||
PlayerCharacter->AddControllerYawInput(RecoilYaw * CurrentGun->RecoilForceMultiplier);
|
||
}
|
||
|
||
void UShootingComponent::MeleAttack()
|
||
{
|
||
AActor* HitActor = ExecuteLineTrace(MeleRange);
|
||
if (HitActor)
|
||
{
|
||
IDamageable::Execute_TakeDamage(HitActor, MeleDamageValue);
|
||
}
|
||
}
|
||
|
||
AActor* UShootingComponent::ExecuteLineTrace(float LineRange)
|
||
{
|
||
FVector ForwardVector = PlayerCharacter->GetActorForwardVector();
|
||
FVector ViewLocation;
|
||
FRotator ViewRotation;
|
||
PlayerCharacter->GetController()->GetPlayerViewPoint(ViewLocation, ViewRotation);
|
||
|
||
FVector EndVector = ViewLocation + ForwardVector * LineRange;
|
||
|
||
FHitResult Hit;
|
||
FCollisionQueryParams QueryParams;
|
||
QueryParams.AddIgnoredActor(PlayerCharacter);
|
||
|
||
// DEBUG
|
||
if (bShowDebugLine)
|
||
DrawDebugLine(GetWorld(), ViewLocation, EndVector, FColor::Red, false, 5.0f, 0, 1.0f);
|
||
|
||
if (GetWorld()->LineTraceSingleByChannel(Hit, ViewLocation, EndVector, ECC_Visibility, QueryParams) &&
|
||
IsValid(Hit.GetActor()) && Hit.GetActor()->Implements<UDamageable>())
|
||
{
|
||
return Hit.GetActor();
|
||
}
|
||
|
||
return nullptr;
|
||
}
|
||
|
||
void UShootingComponent::Reload()
|
||
{
|
||
if (!IsValid(CurrentGun) || bIsReloading) return;
|
||
|
||
bIsReloading = true;
|
||
StopAiming();
|
||
|
||
CurrentGun->CurrentAmmo = CurrentGun->MaxAmmo;
|
||
PlayerCharacter->GetWorldTimerManager().SetTimer(ReloadTimer, this, &UShootingComponent::ReloadCompleted, CurrentGun->ReloadTime, false);
|
||
|
||
UE_LOG(LogTemp, Display, TEXT("Reloaded. Ammo: %d/%d"), CurrentGun->CurrentAmmo, CurrentGun->MaxAmmo); // Docelowo tutaj wywo<77>anie UI aktualizuj<75>ce stan ammo
|
||
}
|
||
|
||
void UShootingComponent::PickUpGun(AGunBase* gunItem)
|
||
{
|
||
if (IsValid(CurrentGun) && IsValid(SecondaryGun))
|
||
DropGun();
|
||
|
||
AGunBase* NewGun = NewObject<AGunBase>();
|
||
|
||
NewGun->MaxRange = gunItem->MaxRange;
|
||
NewGun->DamageValue = gunItem->DamageValue;
|
||
NewGun->FireRateCooldown = gunItem->FireRateCooldown;
|
||
NewGun->RecoilForceMultiplier = gunItem->RecoilForceMultiplier;
|
||
NewGun->ReloadTime = gunItem->ReloadTime;
|
||
NewGun->CurrentAmmo = gunItem->CurrentAmmo;
|
||
NewGun->MaxAmmo = gunItem->MaxAmmo;
|
||
NewGun->SceneItemClass = gunItem->GetClass();
|
||
|
||
if (IsValid(CurrentGun))
|
||
SecondaryGun = NewGun;
|
||
else
|
||
CurrentGun = NewGun;
|
||
}
|
||
|
||
bool UShootingComponent::PickUpThrow(AThrowableBase* ThrowItem)
|
||
{
|
||
AThrowableBase* NewThrowable = NewObject<AThrowableBase>();
|
||
|
||
if (IsValid(ThrowableItem))
|
||
{
|
||
if (ThrowableItem->GetClass() == NewThrowable->GetClass())
|
||
{
|
||
if (ThrowableItem->Quantity + ThrowItem->Quantity >= ThrowableItem->MaxQuantity)
|
||
{
|
||
ThrowableItem->Quantity = ThrowableItem->MaxQuantity;
|
||
return false;
|
||
}
|
||
|
||
ThrowableItem->Quantity += ThrowItem->Quantity;
|
||
return true;
|
||
|
||
}
|
||
|
||
DropThrow();
|
||
}
|
||
|
||
NewThrowable->Damage = ThrowItem->Damage;
|
||
NewThrowable->Quantity = ThrowItem->Quantity;
|
||
NewThrowable->Radius = ThrowItem->Radius;
|
||
NewThrowable->ThrowableType = ThrowItem->ThrowableType;
|
||
NewThrowable->SceneItemClass = ThrowItem->GetClass();
|
||
|
||
ThrowableItem = NewThrowable;
|
||
return true;
|
||
}
|
||
|
||
void UShootingComponent::DropGun()
|
||
{
|
||
if (!IsValid(CurrentGun)) return;
|
||
|
||
StopAiming();
|
||
|
||
FVector ForwardVector = PlayerCharacter->GetActorForwardVector();
|
||
FVector PlayerPos = PlayerCharacter->GetActorLocation();
|
||
FVector DroppedGunPos = PlayerPos + (ForwardVector * DropGunRange);
|
||
|
||
FTransform DroppedGunTransform = PlayerCharacter->GetActorTransform();
|
||
DroppedGunTransform.SetLocation(DroppedGunPos);
|
||
|
||
AGunBase* DroppedGun = GetWorld()->SpawnActor<AGunBase>(CurrentGun->SceneItemClass, DroppedGunTransform);
|
||
|
||
if (DroppedGun)
|
||
{
|
||
DroppedGun->MaxRange = CurrentGun->MaxRange;
|
||
DroppedGun->DamageValue = CurrentGun->DamageValue;
|
||
DroppedGun->FireRateCooldown = CurrentGun->FireRateCooldown;
|
||
DroppedGun->RecoilForceMultiplier = CurrentGun->RecoilForceMultiplier;
|
||
DroppedGun->ReloadTime = CurrentGun->ReloadTime;
|
||
DroppedGun->CurrentAmmo = CurrentGun->CurrentAmmo;
|
||
DroppedGun->MaxAmmo = CurrentGun->MaxAmmo;
|
||
|
||
CurrentGun->Destroy();
|
||
CurrentGun = nullptr;
|
||
}
|
||
}
|
||
|
||
void UShootingComponent::DropThrow()
|
||
{
|
||
if (!IsValid(ThrowableItem)) return;
|
||
|
||
FVector ForwardVector = PlayerCharacter->GetActorForwardVector();
|
||
FVector DroppedPos = PlayerCharacter->GetActorLocation() + (ForwardVector * 100.f);
|
||
|
||
FTransform DroppedTransform = PlayerCharacter->GetActorTransform();
|
||
DroppedTransform.SetLocation(DroppedPos);
|
||
|
||
AThrowableBase* DropedItem = GetWorld()->SpawnActor<AThrowableBase>(ThrowableItem->SceneItemClass, DroppedTransform);
|
||
|
||
if (DropedItem)
|
||
{
|
||
ThrowableItem->Quantity--;
|
||
DropedItem->Damage = ThrowableItem->Damage;
|
||
DropedItem->Radius = ThrowableItem->Radius;
|
||
DropedItem->Quantity = ThrowableItem->Quantity;
|
||
DropedItem->ThrowableType = ThrowableItem->ThrowableType;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
void UShootingComponent::ResetFireCooldown()
|
||
{
|
||
bCanShoot = true;
|
||
}
|
||
|
||
void UShootingComponent::ReloadCompleted()
|
||
{
|
||
bIsReloading = false;
|
||
}
|
||
|
||
void UShootingComponent::SelectGun(bool bSelectFirstSlot)
|
||
{
|
||
if (bSelectFirstSlot != bIsFirstGunSelected)
|
||
SwitchGun();
|
||
}
|
||
|
||
void UShootingComponent::SwitchGun()
|
||
{
|
||
AGunBase* temp = CurrentGun;
|
||
CurrentGun = SecondaryGun;
|
||
SecondaryGun = temp;
|
||
|
||
bIsFirstGunSelected = !bIsFirstGunSelected;
|
||
StopAiming();
|
||
|
||
// Debug info
|
||
if (bIsFirstGunSelected)
|
||
{
|
||
UE_LOG(LogTemp, Display, TEXT("Zmiana broni na broń 1"));
|
||
}
|
||
else
|
||
{
|
||
UE_LOG(LogTemp, Display, TEXT("Zmiana broni na broń 2"));
|
||
}
|
||
}
|
||
|
||
void UShootingComponent::StartAiming()
|
||
{
|
||
if (IsValid(CurrentGun))
|
||
{
|
||
PlayerCharacter->bIsAimingMode = true;
|
||
PlayerCharacter->GetCharacterMovement()->MaxWalkSpeed = PlayerCharacter->WalkSpeed * AimingMoveSpeedScale;
|
||
|
||
TargetFOV = CurrentGun->AimingFOV;
|
||
}
|
||
}
|
||
|
||
void UShootingComponent::StopAiming()
|
||
{
|
||
PlayerCharacter->bIsAimingMode = false;
|
||
PlayerCharacter->GetCharacterMovement()->MaxWalkSpeed = PlayerCharacter->WalkSpeed;
|
||
|
||
TargetFOV = DefaultFOV;
|
||
}
|
||
|
||
void UShootingComponent::Throw()
|
||
{
|
||
if (IsValid(ThrowableItem))
|
||
{
|
||
FVector DroppedPos = CameraManager->GetCameraLocation() + CameraManager->GetActorForwardVector() * 100.f;
|
||
|
||
FTransform DroppedTransform = PlayerCharacter->GetActorTransform();
|
||
DroppedTransform.SetLocation(DroppedPos);
|
||
|
||
AThrowableBase* ThrowedItem = GetWorld()->SpawnActor<AThrowableBase>(ThrowableItem->SceneItemClass, DroppedTransform);
|
||
|
||
if (ThrowedItem)
|
||
{
|
||
ThrowableItem->Quantity--;
|
||
ThrowedItem->Damage = ThrowableItem->Damage;
|
||
ThrowedItem->Radius = ThrowableItem->Radius;
|
||
ThrowedItem->Quantity = 1;
|
||
ThrowedItem->ThrowableType = ThrowableItem->ThrowableType;
|
||
|
||
FVector ThrowVector = (ThrowedItem->GetActorLocation() - PlayerCharacter->GetActorLocation()).GetSafeNormal();
|
||
ThrowedItem->Mesh->SetPhysicsLinearVelocity(ThrowVector * 1000.f); // Need force to change to the game
|
||
|
||
if (ThrowableItem->Quantity <= 0)
|
||
{
|
||
ThrowableItem->Destroy();
|
||
ThrowableItem = nullptr;
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
// Called every frame
|
||
void UShootingComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
|
||
{
|
||
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
|
||
|
||
float CurrentFOV = CameraManager->GetFOVAngle();
|
||
float NewFOV = FMath::FInterpTo(CurrentFOV, TargetFOV, DeltaTime, AimingAnimationSpeed);
|
||
CameraManager->SetFOV(NewFOV);
|
||
}
|