// 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(TEXT("WeaponMesh")); SetRootComponent(WeaponMesh); WeaponMesh->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Block); WeaponMesh->SetCollisionResponseToChannel(ECollisionChannel::ECC_Pawn, ECollisionResponse::ECR_Ignore); WeaponMesh->SetCollisionEnabled(ECollisionEnabled::NoCollision); AreaSphere = CreateDefaultSubobject(TEXT("AreaSphere")); AreaSphere->SetupAttachment(RootComponent); AreaSphere->SetCollisionResponseToAllChannels(ECollisionResponse::ECR_Ignore); AreaSphere->SetCollisionEnabled(ECollisionEnabled::NoCollision); PickupWidget = CreateDefaultSubobject(TEXT("PickupWidget")); PickupWidget->SetupAttachment(RootComponent); } void AWeapon::GetLifetimeReplicatedProps(TArray& 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(OtherActor); if (BlasterCharacter) { BlasterCharacter->SetOverlappingWeapon(this); } } void AWeapon::OnSphereEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex) { ABlasterCharacter* BlasterCharacter = Cast(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(GetOwner()) : OwnerCharacter; if (OwnerCharacter) { OwnerController = OwnerController == nullptr ? Cast(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( 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(); }