// 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(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, 1.0f, 0, 1.0f); if (GetWorld()->LineTraceSingleByChannel(Hit, ViewLocation, EndVector, ECC_Visibility, QueryParams) && IsValid(Hit.GetActor()) && Hit.GetActor()->Implements()) { 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�anie UI aktualizuj�ce stan ammo } void UShootingComponent::PickUpGun(AGunBase* gunItem) { if (IsValid(CurrentGun) && IsValid(SecondaryGun)) DropGun(); AGunBase* NewGun = NewObject(); 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(); 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(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(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() // Wymaga dopracowania { if (IsValid(ThrowableItem)) { FVector ForwardVector = PlayerCharacter->GetActorForwardVector(); FVector DroppedPos = PlayerCharacter->GetActorLocation() + (ForwardVector * 100.f); FTransform DroppedTransform = PlayerCharacter->GetActorTransform(); DroppedTransform.SetLocation(DroppedPos); AThrowableBase* ThrowedItem = GetWorld()->SpawnActor(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 * 800.f); 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); }