ExoWest/Source/Exo/Private/Characters/Components/ShootingComponent.cpp

328 lines
9.6 KiB
C++
Raw Blame History

// Fill out your copyright notice in the Description page of Project Settings.
#include "Characters/Components/ShootingComponent.h"
#include "Items/ThrowableBase.h"
UShootingComponent::UShootingComponent()
{
PrimaryComponentTick.bCanEverTick = true;
}
void UShootingComponent::BeginPlay()
{
Super::BeginPlay();
PlayerCharacter = Cast<AExoPlayerCharacter>(GetOwner());
CameraManager = GetWorld()->GetFirstPlayerController()->PlayerCameraManager;
DefaultFOV = CameraManager->GetFOVAngle();
TargetFOV = DefaultFOV;
}
void UShootingComponent::Shoot()
{
if (!IsValid(CurrentGunBase) || CurrentGunBase->CurrentAmmo == 0 || bIsReloading || !bCanShoot) return;
bCanShoot = false;
CurrentGunBase->CurrentAmmo--;
AActor* HitActor = ExecuteLineTrace(CurrentGunBase->MaxRange);
if (HitActor)
{
IDamageable::Execute_TakeDamage(HitActor, CurrentGunBase->DamageValue);
UE_LOG(LogTemp, Display, TEXT("Shoot. Ammo: %d/%d"), CurrentGunBase->CurrentAmmo, CurrentGunBase->MaxAmmo); // Docelowo tutaj wywołanie UI aktualizujące stan ammo
}
PlayerCharacter->GetWorldTimerManager().SetTimer(ShootCooldownTimer, this, &UShootingComponent::ResetFireCooldown, CurrentGunBase->FireRateCooldown, false);
// Odrzut
float RecoilPitch = FMath::RandRange(-1.0f, -0.5f);
float RecoilYaw = FMath::RandRange(-0.5f, 0.5f);
PlayerCharacter->AddControllerPitchInput(RecoilPitch * CurrentGunBase->RecoilForceMultiplier);
PlayerCharacter->AddControllerYawInput(RecoilYaw * CurrentGunBase->RecoilForceMultiplier);
}
void UShootingComponent::MeleAttack()
{
AActor* HitActor = ExecuteLineTrace(MeleRange);
if (HitActor)
{
IDamageable::Execute_TakeDamage(HitActor, MeleDamageValue);
}
}
AActor* UShootingComponent::ExecuteLineTrace(float LineRange)
{
FVector ForwardVector = CameraManager->GetActorForwardVector();
FVector ViewLocation = CameraManager->GetCameraLocation();
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(CurrentGunBase) || bIsReloading) return;
bIsReloading = true;
StopAiming();
CurrentGunBase->CurrentAmmo = CurrentGunBase->MaxAmmo;
PlayerCharacter->GetWorldTimerManager().SetTimer(ReloadTimer, this, &UShootingComponent::ReloadCompleted, CurrentGunBase->ReloadTime, false);
UE_LOG(LogTemp, Display, TEXT("Reloaded. Ammo: %d/%d"), CurrentGunBase->CurrentAmmo, CurrentGunBase->MaxAmmo); // Docelowo tutaj wywo<77>anie UI aktualizuj<75>ce stan ammo
}
bool UShootingComponent::AddAmmo(EAmmoType CheckingAmmo, int AddValue)
{
// Adding ammo only if type is compatible
if (CurrentGunBase && CurrentGunBase->AmmoType == CheckingAmmo)
{
CurrentGunBase->AddAmmo(AddValue);
return true;
}
if (SecondaryGunBase && SecondaryGunBase->AmmoType == CheckingAmmo)
{
SecondaryGunBase->AddAmmo(AddValue);
return true;
}
return false;
}
void UShootingComponent::PickUpGun(UStaticMeshComponent* PickedGunMesh)
{
if (IsValid(CurrentGunBase) && IsValid(SecondaryGunBase))
DropGun();
FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, EAttachmentRule::SnapToTarget,
EAttachmentRule::KeepRelative, true);
PickedGunMesh->SetSimulatePhysics(false);
PickedGunMesh->SetCastShadow(false);
PickedGunMesh->AttachToComponent(PlayerCharacter->Weapon, AttachmentRules, FName(TEXT("GripPoint")));
AGunBase* PickedGunBase = Cast<AGunBase>(PickedGunMesh->GetOwner());
if (IsValid(CurrentGunBase))
{
SecondaryGunBase = PickedGunBase;
SecondaryGunMesh = PickedGunMesh;
SecondaryGunMesh->SetVisibility(false);
}
else
{
CurrentGunBase = PickedGunBase;
CurrentGunMesh = PickedGunMesh;
}
}
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(CurrentGunBase)) return;
StopAiming();
FDetachmentTransformRules DetachmentRules(EDetachmentRule::KeepRelative, EDetachmentRule::KeepRelative,
EDetachmentRule::KeepRelative, false);
CurrentGunMesh->DetachFromComponent(DetachmentRules);
CurrentGunMesh->SetSimulatePhysics(true);
CurrentGunMesh->bCastDynamicShadow = true;
CurrentGunMesh->CastShadow = true;
CurrentGunMesh = nullptr;
CurrentGunBase = 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* tempBase = CurrentGunBase;
CurrentGunBase = SecondaryGunBase;
SecondaryGunBase = tempBase;
UStaticMeshComponent* tempMesh = CurrentGunMesh;
CurrentGunMesh = SecondaryGunMesh;
SecondaryGunMesh = tempMesh;
if (IsValid(SecondaryGunMesh))
SecondaryGunMesh->SetVisibility(false);
if (IsValid(CurrentGunMesh))
CurrentGunMesh->SetVisibility(true);
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(CurrentGunBase))
{
PlayerCharacter->bIsAimingMode = true;
PlayerCharacter->GetCharacterMovement()->MaxWalkSpeed = PlayerCharacter->WalkSpeed * AimingMoveSpeedScale;
TargetFOV = CurrentGunBase->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;
}
}
}
}
bool UShootingComponent::IsHoldingGun()
{
if (IsValid(CurrentGunBase))
return true;
return false;
}
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);
}