328 lines
9.6 KiB
C++
328 lines
9.6 KiB
C++
// 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);
|
||
}
|