270 lines
7.1 KiB
C++
270 lines
7.1 KiB
C++
// 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<FLifetimeProperty>& 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<ABlasterPlayerController>(Character->Controller) : Controller;
|
|
if (Controller)
|
|
{
|
|
HUD = HUD == nullptr ? Cast<ABlasterHUD>(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;
|
|
if (Character)
|
|
{
|
|
float DistanceToCharacter = (Character->GetActorLocation() - Start).Size();
|
|
Start += CrosshairWorldDirection * (DistanceToCharacter + 60.f);
|
|
}
|
|
FVector End = Start + CrosshairWorldDirection * TRACE_LENGTH;
|
|
|
|
GetWorld()->LineTraceSingleByChannel(
|
|
TraceHitResult,
|
|
Start,
|
|
End,
|
|
ECollisionChannel::ECC_Visibility
|
|
);
|
|
if (TraceHitResult.GetActor() && TraceHitResult.GetActor()->Implements<UInteractWithCrosshairInterface>())
|
|
{
|
|
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;
|
|
}
|