blaster/Source/Blaster/Weapon/Weapon.cpp

222 lines
5.6 KiB
C++

// Fill out your copyright notice in the Description page of Project Settings.
#include "Weapon.h"
#include "Casing.h"
#include "Blaster/Character/BlasterCharacter.h"
#include "Blaster/PlayerController/BlasterPlayerController.h"
#include "Components/SphereComponent.h"
#include "Components/WidgetComponent.h"
#include "Engine/SkeletalMeshSocket.h"
#include "Net/UnrealNetwork.h"
AWeapon::AWeapon()
{
PrimaryActorTick.bCanEverTick = false;
bReplicates = true;
SetReplicateMovement(true);
WeaponMesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("WeaponMesh"));
SetRootComponent(WeaponMesh);
WeaponMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Block);
WeaponMesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore);
WeaponMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
AreaSphere = CreateDefaultSubobject<USphereComponent>(TEXT("AreaSphere"));
AreaSphere->SetupAttachment(RootComponent);
AreaSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore);
AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision);
PickupWidget = CreateDefaultSubobject<UWidgetComponent>(TEXT("PickupWidget"));
PickupWidget->SetupAttachment(RootComponent);
}
void AWeapon::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(AWeapon, WeaponState);
DOREPLIFETIME(AWeapon, Ammo);
}
void AWeapon::BeginPlay()
{
Super::BeginPlay();
if (HasAuthority())
{
AreaSphere->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
AreaSphere->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Overlap);
AreaSphere->OnComponentBeginOverlap.AddDynamic(this, &AWeapon::OnSphereOverlap);
AreaSphere->OnComponentEndOverlap.AddDynamic(this, &AWeapon::OnSphereEndOverlap);
}
if (PickupWidget)
{
PickupWidget->SetVisibility(false);
}
}
void AWeapon::OnSphereOverlap(UPrimitiveComponent* OverlappedComponent,
AActor* OtherActor,
UPrimitiveComponent* OtherComp,
int32 OtherBodyIndex,
bool bFromSweep,
const FHitResult& SweepResult)
{
ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(OtherActor);
if (BlasterCharacter)
{
BlasterCharacter->SetOverlappingWeapon(this);
}
}
void AWeapon::OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor,
UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
ABlasterCharacter* BlasterCharacter = Cast<ABlasterCharacter>(OtherActor);
if (BlasterCharacter)
{
BlasterCharacter->SetOverlappingWeapon(nullptr);
}
}
void AWeapon::OnRep_Owner()
{
Super::OnRep_Owner();
if (Owner == nullptr)
{
OwnerCharacter = nullptr;
OwnerController = nullptr;
} else
{
SetHUDAmmo();
}
}
void AWeapon::SetHUDAmmo()
{
OwnerCharacter = OwnerCharacter == nullptr ? Cast<ABlasterCharacter>(GetOwner()) : OwnerCharacter;
if (OwnerCharacter)
{
OwnerController = OwnerController == nullptr ? Cast<ABlasterPlayerController>(OwnerCharacter->Controller) : OwnerController;
if (OwnerController)
{
OwnerController->SetHUDWeaponAmmo(Ammo);
}
}
}
void AWeapon::SpendRound()
{
Ammo = FMath::Clamp(Ammo - 1, 0, MagCapacity);
SetHUDAmmo();
}
void AWeapon::OnRep_Ammo()
{
SetHUDAmmo();
}
void AWeapon::SetWeaponState(EWeaponState State)
{
WeaponState = State;
switch (WeaponState)
{
case EWeaponState::EWS_Equipped:
ShowPickupWidget(false);
GetAreaSphere()->SetCollisionEnabled(ECollisionEnabled::NoCollision);
WeaponMesh->SetSimulatePhysics(false);
WeaponMesh->SetEnableGravity(false);
WeaponMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
case EWeaponState::EWS_Dropped:
if (HasAuthority())
{
GetAreaSphere()->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
}
WeaponMesh->SetSimulatePhysics(true);
WeaponMesh->SetEnableGravity(true);
WeaponMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
break;
}
}
bool AWeapon::IsEmpty()
{
return Ammo <= 0;
}
void AWeapon::OnRep_WeaponState()
{
switch (WeaponState)
{
case EWeaponState::EWS_Equipped:
ShowPickupWidget(false);
WeaponMesh->SetSimulatePhysics(false);
WeaponMesh->SetEnableGravity(false);
WeaponMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision);
break;
case EWeaponState::EWS_Dropped:
WeaponMesh->SetSimulatePhysics(true);
WeaponMesh->SetEnableGravity(true);
WeaponMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
break;
}
}
void AWeapon::ShowPickupWidget(bool bShowWidget)
{
if (PickupWidget)
{
PickupWidget->SetVisibility(bShowWidget);
}
}
void AWeapon::Fire(const FVector& HitTarget)
{
if (FireAnimation)
{
WeaponMesh->PlayAnimation(FireAnimation, false);
}
if (CasingClass)
{
const USkeletalMeshSocket* AmmoEjectSocket = WeaponMesh->GetSocketByName(FName("AmmoEject"));
if (AmmoEjectSocket)
{
FTransform SocketTransform = AmmoEjectSocket->GetSocketTransform(WeaponMesh);
UWorld* World = GetWorld();
if (World)
{
World->SpawnActor<ACasing>(
CasingClass,
SocketTransform.GetLocation(),
SocketTransform.GetRotation().Rotator()
);
}
}
}
SpendRound();
}
void AWeapon::Dropped()
{
SetWeaponState(EWeaponState::EWS_Dropped);
const FDetachmentTransformRules DetachRules(EDetachmentRule::KeepWorld, true);
WeaponMesh->DetachFromComponent(DetachRules);
SetOwner(nullptr);
OwnerCharacter = nullptr;
OwnerController = nullptr;
}
void AWeapon::AddAmmo(int32 Amount)
{
Ammo = FMath::Clamp(Ammo - Amount, 0, MagCapacity);
SetHUDAmmo();
}