// Fill out your copyright notice in the Description page of Project Settings. #include "CombatComponent.h" #include "Blaster/Character/BlasterCharacter.h" #include "Blaster/PlayerController/BlasterPlayerController.h" #include "Blaster/Weapon/Weapon.h" #include "Camera/CameraComponent.h" #include "Engine/SkeletalMeshSocket.h" #include "GameFramework/CharacterMovementComponent.h" #include "Kismet/GameplayStatics.h" #include "Net/UnrealNetwork.h" UCombatComponent::UCombatComponent() { PrimaryComponentTick.bCanEverTick = true; BaseWalkSpeed = 600.f; AimWalkSpeed = 350.f; } void UCombatComponent::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const { Super::GetLifetimeReplicatedProps(OutLifetimeProps); DOREPLIFETIME(UCombatComponent, EquippedWeapon); DOREPLIFETIME(UCombatComponent, bAiming); } void UCombatComponent::BeginPlay() { Super::BeginPlay(); if (Character) { Character->GetCharacterMovement()->MaxWalkSpeed = BaseWalkSpeed; if (Character->GetFollowCamera()) { DefaultFOV = Character->GetFollowCamera()->FieldOfView; CurrentFOV = DefaultFOV; } } } void UCombatComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); if (Character && Character->IsLocallyControlled()) { FHitResult HitResult; TraceUnderCrosshairs(HitResult); HitTarget = HitResult.ImpactPoint; SetHUDCrosshairs(DeltaTime); InterpFOV(DeltaTime); } } void UCombatComponent::SetHUDCrosshairs(float DeltaTime) { if (Character == nullptr || Character->Controller == nullptr) return; Controller = Controller == nullptr ? Cast(Character->Controller) : Controller; if (Controller) { HUD = HUD == nullptr ? Cast(Controller->GetHUD()) : HUD; if (HUD) { if (EquippedWeapon) { HUDPackage.CrosshairsCenter = EquippedWeapon->CrosshairsCenter; HUDPackage.CrosshairsLeft = EquippedWeapon->CrosshairsLeft; HUDPackage.CrosshairsRight = EquippedWeapon->CrosshairsRight; HUDPackage.CrosshairsTop = EquippedWeapon->CrosshairsTop; HUDPackage.CrosshairsBottom = EquippedWeapon->CrosshairsBottom; } else { HUDPackage.CrosshairsCenter = nullptr; HUDPackage.CrosshairsLeft = nullptr; HUDPackage.CrosshairsRight = nullptr; HUDPackage.CrosshairsTop = nullptr; HUDPackage.CrosshairsBottom = nullptr; } // Calculate crosshair spread // Velocity [0, 600] -> Spread [0, 1] const FVector2D WalkSpeedRange(0.f, Character->GetCharacterMovement()->MaxWalkSpeed); const FVector2D VelocityMultiplierRange(0.f, 1.f); FVector Velocity = Character->GetVelocity(); Velocity.Z = 0.f; CrosshairVelocityFactor = FMath::GetMappedRangeValueClamped(WalkSpeedRange, VelocityMultiplierRange, Velocity.Size()); if (Character->GetCharacterMovement()->IsFalling()) { CrosshairInAirFactor = FMath::FInterpTo(CrosshairInAirFactor, 2.25f, DeltaTime, 2.25f); } else { CrosshairInAirFactor = FMath::FInterpTo(CrosshairInAirFactor, 0.f, DeltaTime, 30.f); } if (bAiming) { CrosshairAimFactor = FMath::FInterpTo(CrosshairAimFactor, 0.58f, DeltaTime, 30.f); } else { CrosshairAimFactor = FMath::FInterpTo(CrosshairAimFactor, 0.f, DeltaTime, 30.f); } CrosshairShootingFactor = FMath::FInterpTo(CrosshairShootingFactor, 0.f, DeltaTime, 40.f); HUDPackage.CrosshairSpread = 0.5f + CrosshairVelocityFactor + CrosshairInAirFactor - CrosshairAimFactor + CrosshairShootingFactor; HUD->SetHUDPackage(HUDPackage); } } } void UCombatComponent::InterpFOV(float DeltaTime) { if (EquippedWeapon == nullptr) return; if (bAiming) { CurrentFOV = FMath::FInterpTo(CurrentFOV, EquippedWeapon->GetZoomedFOV(), DeltaTime, EquippedWeapon->GetZoomInterpSpeed()); } else { CurrentFOV = FMath::FInterpTo(CurrentFOV, DefaultFOV, DeltaTime, ZoomInterpSpeed); } if (Character && Character->GetFollowCamera()) { Character->GetFollowCamera()->SetFieldOfView(CurrentFOV); } } void UCombatComponent::SetAiming(bool bIsAiming) { bAiming = bIsAiming; ServerSetAiming(bIsAiming); if (Character) { Character->GetCharacterMovement()->MaxWalkSpeed = bIsAiming ? AimWalkSpeed : BaseWalkSpeed; } } void UCombatComponent::ServerSetAiming_Implementation(bool bIsAiming) { bAiming = bIsAiming; if (Character) { Character->GetCharacterMovement()->MaxWalkSpeed = bIsAiming ? AimWalkSpeed : BaseWalkSpeed; } } void UCombatComponent::OnRep_EquippedWeapon() { if (EquippedWeapon && Character) { Character->GetCharacterMovement()->bOrientRotationToMovement = false; Character->bUseControllerRotationYaw = true; } } void UCombatComponent::FireButtonPressed(bool bPressed) { bFireButtonPressed = bPressed; if (bFireButtonPressed) { FHitResult HitResult; TraceUnderCrosshairs(HitResult); ServerFire(HitResult.ImpactPoint); if (EquippedWeapon) { CrosshairShootingFactor = 0.75f; } } } void UCombatComponent::TraceUnderCrosshairs(FHitResult& TraceHitResult) { FVector2d ViewPortSize; if (GEngine && GEngine->GameViewport) { GEngine->GameViewport->GetViewportSize(ViewPortSize); } FVector2d CrosshairLocation(ViewPortSize.X / 2.f, ViewPortSize.Y / 2.0f); FVector CrosshairWorldPosition; FVector CrosshairWorldDirection; bool bScreenToWorld = UGameplayStatics::DeprojectScreenToWorld( UGameplayStatics::GetPlayerController(this, 0), CrosshairLocation, CrosshairWorldPosition, CrosshairWorldDirection ); if (bScreenToWorld) { FVector Start = CrosshairWorldPosition; FVector End = Start + CrosshairWorldDirection * TRACE_LENGTH; GetWorld()->LineTraceSingleByChannel( TraceHitResult, Start, End, ECollisionChannel::ECC_Visibility ); if (TraceHitResult.GetActor() && TraceHitResult.GetActor()->Implements()) { HUDPackage.CrosshairColor = FLinearColor::Red; } else { HUDPackage.CrosshairColor = FLinearColor::White; } if (!TraceHitResult.bBlockingHit) TraceHitResult.ImpactPoint = End; } } void UCombatComponent::ServerFire_Implementation(const FVector_NetQuantize& TraceHitTarget) { MulticastFire(TraceHitTarget); } void UCombatComponent::MulticastFire_Implementation(const FVector_NetQuantize& TraceHitTarget) { if (EquippedWeapon == nullptr) return; if (Character) { Character->PlayFireMontage(bAiming); EquippedWeapon->Fire(TraceHitTarget); } } void UCombatComponent::EquipWeapon(AWeapon* WeaponToEquip) { if (Character == nullptr || WeaponToEquip == nullptr) return; EquippedWeapon = WeaponToEquip; EquippedWeapon->SetWeaponState(EWeaponState::EWS_Equipped); const USkeletalMeshSocket* HandSocket = Character->GetMesh()->GetSocketByName(FName("RightHandSocket")); if (HandSocket) { HandSocket->AttachActor(EquippedWeapon, Character->GetMesh()); } EquippedWeapon->SetOwner(Character); Character->GetCharacterMovement()->bOrientRotationToMovement = false; Character->bUseControllerRotationYaw = true; }