Update Character for Animation System Integration

This commit is contained in:
Philip W 2024-03-13 16:23:20 +00:00
parent a8d2f57778
commit 0cbfbd0625
35 changed files with 101 additions and 400 deletions

Binary file not shown.

Binary file not shown.

BIN
EndlessVendetta/Content/FirstPerson/BPGM_Vendetta.uasset (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -30,21 +30,6 @@ AEndlessVendettaCharacter::AEndlessVendettaCharacter()
GetCharacterMovement()->GetNavAgentPropertiesRef().bCanCrouch = true;
// Set size for collision capsule
GetCapsuleComponent()->InitCapsuleSize(55.f, 96.0f);
// // Create a CameraComponent
// FirstPersonCameraComponent = CreateDefaultSubobject<UCameraComponent>(TEXT("FirstPersonCamera"));
// FirstPersonCameraComponent->SetupAttachment(GetCapsuleComponent());
// FirstPersonCameraComponent->SetRelativeLocation(FVector(-10.f, 0.f, 60.f)); // Position the camera
// FirstPersonCameraComponent->bUsePawnControlRotation = true;
//
// // Create a mesh component that will be used when being viewed from a '1st person' view (when controlling this pawn)
// Mesh1P = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("CharacterMesh1P"));
// Mesh1P->SetOnlyOwnerSee(true);
// Mesh1P->SetupAttachment(FirstPersonCameraComponent);
// Mesh1P->bCastDynamicShadow = false;
// Mesh1P->CastShadow = false;
// //Mesh1P->SetRelativeRotation(FRotator(0.9f, -19.19f, 5.2f));
// Mesh1P->SetRelativeLocation(FVector(-30.f, 0.f, -150.f));
}
void AEndlessVendettaCharacter::IncrementRestrictedBoundsCount()
@ -67,10 +52,23 @@ void AEndlessVendettaCharacter::DecrementRestrictedBoundsCount()
}
}
void AEndlessVendettaCharacter::ReloadAnimationComplete()
{
bIsReloading = false;
}
void AEndlessVendettaCharacter::SetOverlayState(const EOverlayState OverlayState) const
{
SetOverlayStateEvent.Broadcast(OverlayState);
}
void AEndlessVendettaCharacter::BeginPlay()
{
// Call the base class
Super::BeginPlay();
FirstPersonArms = Cast<USkeletalMeshComponent>(GetComponentsByTag(USkeletalMeshComponent::StaticClass(), FName("FirstPersonArms"))[0]);
HeldWeapon = Cast<UChildActorComponent>(GetComponentsByTag(UChildActorComponent::StaticClass(), FName("Weapon"))[0]);
bIsCurrentlyHoldingWeapon = false;
UEVGameInstance* GI = Cast<UEVGameInstance>(GetWorld()->GetGameInstance());
if (IsValid(GI->MainSaveGameInstanceRef))
@ -388,7 +386,7 @@ void AEndlessVendettaCharacter::EquipPrimary()
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, TEXT("IsPrimaryWeapon valid check running"));
PrimaryWeapon->DetachFromActor(DetatchRules);
PrimaryWeapon->AttachToComponent(Mesh1P, AttachmentRules, FName("UnEquipGunSocket"));
PrimaryWeapon->AttachToComponent(FirstPersonArms, AttachmentRules, FName("UnEquipGunSocket"));
PrimaryWeapon->SetActorHiddenInGame(true);
PrimaryWeapon->SetActorEnableCollision(false);
this->GetFirstPersonCameraComponent()->SetFieldOfView(90);
@ -397,6 +395,7 @@ void AEndlessVendettaCharacter::EquipPrimary()
bHasRifle = false;
GLog->Log("Primary Weapon Put Away");
bIsCurrentlyHoldingWeapon = false;
SetOverlayState(EOverlayState::Default);
//this is for philips stat viewer thingy
Cast<AEndlessVendettaGameMode>(GetWorld()->GetAuthGameMode())->SendEvent("DeEquip", "Pri");
return;
@ -411,27 +410,32 @@ void AEndlessVendettaCharacter::EquipPrimary()
if (!IsValid(PrimaryWeapon))
{
bHasRifle = true;
if (!bIsPrimaryWeaponCreated)
{
PrimaryWeaponActor = GetWorld()->SpawnActor<AActor>(PrimaryWeaponClass, spawnParams);
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Red, TEXT("Spawning weapon"));
PrimaryWeaponActor->AttachToComponent(Mesh1P, AttachmentRules, FName("GripPoint"));
PrimaryWeaponActor->AttachToComponent(FirstPersonArms, AttachmentRules, FName("GripPoint"));
PrimaryWeapon = Cast<ABaseWeaponClass>(PrimaryWeaponActor);
PrimaryWeapon->SetActorHiddenInGame(false);
PrimaryWeapon->SetActorEnableCollision(false);
bIsCurrentlyHoldingWeapon = true;
bIsPrimaryWeaponCreated = true;
SetOverlayState(EOverlayState::AssaultRifle);
}
}
//For when you already have all your weapons and ur switching with 1 and 2 or when your picking up a weapon with a weapon in hand
if (PrimaryWeaponClass != nullptr)
{
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Green, TEXT("non ifstatement code running"));
PrimaryWeaponActor->AttachToComponent(Mesh1P, AttachmentRules, FName("GripPoint"));
PrimaryWeaponActor->AttachToComponent(FirstPersonArms, AttachmentRules, FName("GripPoint"));
PrimaryWeapon = Cast<ABaseWeaponClass>(PrimaryWeaponActor);
PrimaryWeapon->SetActorHiddenInGame(false);
PrimaryWeapon->SetActorEnableCollision(false);
GetWorldTimerManager().ClearTimer(PrimaryWeapon->reloadTimerHandle);
bIsCurrentlyHoldingWeapon = true;
bHasRifle = true;
SetOverlayState(EOverlayState::AssaultRifle);
}
}
@ -445,10 +449,8 @@ void AEndlessVendettaCharacter::EquipSecondary()
FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);
FDetachmentTransformRules DetatchRules(EDetachmentRule::KeepWorld, false);
if (bIsReloading) return;
if (IsValid(SecondaryWeapon))
{
SecondaryWeapon->AttachToComponent(Mesh1P, AttachmentRules, FName("UnEquipGunSocket"));
SecondaryWeapon->SetActorHiddenInGame(true);
SecondaryWeapon->SetActorEnableCollision(false);
this->GetFirstPersonCameraComponent()->SetFieldOfView(90);
@ -457,6 +459,7 @@ void AEndlessVendettaCharacter::EquipSecondary()
SecondaryWeapon = nullptr;
bIsCurrentlyHoldingWeapon = false;
bHasRifle = false;
SetOverlayState(EOverlayState::Default);
GLog->Log("Secondary Weapon Put Away");
return;
}
@ -471,21 +474,22 @@ void AEndlessVendettaCharacter::EquipSecondary()
bHasRifle = true;
if (!bIsSecondaryWeaponCreated)
{
SecondaryWeaponActor = GetWorld()->SpawnActor<AActor>(SecondaryWeaponClass, spawnParams);
SecondaryWeaponActor->AttachToComponent(Mesh1P, AttachmentRules, FName("GripPoint"));
HeldWeapon->SetChildActorClass(SecondaryWeaponClass);
SecondaryWeaponActor = HeldWeapon->GetChildActor();
SecondaryWeapon = Cast<ABaseWeaponClass>(SecondaryWeaponActor);
SecondaryWeapon->SetActorHiddenInGame(false);
bIsCurrentlyHoldingWeapon = true;
bIsSecondaryWeaponCreated = true;
SetOverlayState(EOverlayState::Pistol);
}
GLog->Log("Secondary Weapon Equipped");
}
if (SecondaryWeaponClass != nullptr)
{
SecondaryWeaponActor->AttachToComponent(Mesh1P, AttachmentRules, FName("PistolGripPoint"));
SecondaryWeapon = Cast<ABaseWeaponClass>(SecondaryWeaponActor);
SecondaryWeapon->SetActorHiddenInGame(false);
bIsCurrentlyHoldingWeapon = true;
SetOverlayState(EOverlayState::Pistol);
GetWorldTimerManager().ClearTimer(SecondaryWeapon->reloadTimerHandle);
}
}
@ -524,7 +528,7 @@ void AEndlessVendettaCharacter::WeaponSwitcher(AActor* Outhit)
{
PrimaryWeaponActor = GetWorld()->SpawnActor<AActor>(PrimaryWeaponClass, spawnParams);
GEngine->AddOnScreenDebugMessage(-1, 15.f, FColor::Green, TEXT("non ifstatement code running"));
PrimaryWeaponActor->AttachToComponent(Mesh1P, AttachmentRules, FName("GripPoint"));
PrimaryWeaponActor->AttachToComponent(FirstPersonArms, AttachmentRules, FName("GripPoint"));
PrimaryWeapon = Cast<ABaseWeaponClass>(PrimaryWeaponActor);
PrimaryWeapon->SetActorHiddenInGame(false);
GetWorldTimerManager().ClearTimer(PrimaryWeapon->reloadTimerHandle);
@ -568,11 +572,11 @@ void AEndlessVendettaCharacter::FireCaller()
{
if (bIsReloading) return;
if (InPauseMenu) return;
if (IsValid(PrimaryWeapon) && !bIsReloading)
if (IsValid(PrimaryWeapon))
{
PrimaryWeapon->Fire();
}
if (IsValid(SecondaryWeapon) && !bIsReloading)
if (IsValid(SecondaryWeapon))
{
SecondaryWeapon->Fire();
}

View File

@ -21,6 +21,16 @@ class UCameraComponent;
class UAnimMontage;
class USoundBase;
UENUM(BlueprintType)
enum class EOverlayState : uint8
{
Default UMETA(DisplayName = "Default"),
Pistol UMETA(DisplayName = "Pistol"),
AssaultRifle UMETA(DisplayName = "AssaultRifle"),
Shotgun UMETA(DisplayName = "Shotgun"),
Sniper UMETA(DisplayName = "Sniper")
};
UCLASS(config=Game)
class AEndlessVendettaCharacter : public ACharacter
{
@ -29,7 +39,7 @@ class AEndlessVendettaCharacter : public ACharacter
protected:
/** Pawn mesh: 1st person view (arms; seen only by self) */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category=Mesh)
USkeletalMeshComponent* Mesh1P;
USkeletalMeshComponent* FirstPersonArms;
bool InOpenWorld = false;
@ -118,6 +128,8 @@ public:
AActor* PrimaryWeaponActor;
UPROPERTY(BlueprintReadWrite)
AActor* SecondaryWeaponActor;
UPROPERTY(BlueprintReadWrite)
UChildActorComponent* HeldWeapon;
bool bIsPrimaryWeaponCreated = false;
bool bIsSecondaryWeaponCreated = false;
bool bIsWeaponPickedUp = false;
@ -138,9 +150,21 @@ public:
void IncrementRestrictedBoundsCount();
UFUNCTION(BlueprintCallable)
void DecrementRestrictedBoundsCount();
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FReloadAnimationComplete);
UFUNCTION(BlueprintCallable, Category = "Weapon")
void ReloadAnimationComplete();
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FSetOverlayState, EOverlayState, OverlayState);
UPROPERTY(BlueprintAssignable, Category = "Weapon")
FSetOverlayState SetOverlayStateEvent;
UFUNCTION(BlueprintCallable, Category = "Weapon")
void SetOverlayState(EOverlayState OverlayState) const;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FRestrictedAreaStatusChangedSignature, bool, bIsInRestrictedAreaLmao);
UPROPERTY(BlueprintAssignable, Category = "Restricted Area")
FRestrictedAreaStatusChangedSignature RestrictedAreaStatusChanged;
@ -263,8 +287,7 @@ public:
UFUNCTION(BlueprintCallable, Category = "Stealth")
void SetUnCrouch();
/** Returns Mesh1P Sub-object **/
USkeletalMeshComponent* GetMesh1P() const { return Mesh1P; }
USkeletalMeshComponent* GetFirstPersonArms() const { return FirstPersonArms; }
/** Returns FirstPersonCameraComponent Sub-object **/
UCameraComponent* GetFirstPersonCameraComponent() const { return FirstPersonCameraComponent; }

View File

@ -1,43 +0,0 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "EndlessVendettaProjectile.h"
#include "GameFramework/ProjectileMovementComponent.h"
#include "Components/SphereComponent.h"
AEndlessVendettaProjectile::AEndlessVendettaProjectile()
{
// Use a sphere as a simple collision representation
CollisionComp = CreateDefaultSubobject<USphereComponent>(TEXT("SphereComp"));
CollisionComp->InitSphereRadius(5.0f);
CollisionComp->BodyInstance.SetCollisionProfileName("Projectile");
CollisionComp->OnComponentHit.AddDynamic(this, &AEndlessVendettaProjectile::OnHit); // set up a notification for when this component hits something blocking
// Players can't walk on it
CollisionComp->SetWalkableSlopeOverride(FWalkableSlopeOverride(WalkableSlope_Unwalkable, 0.f));
CollisionComp->CanCharacterStepUpOn = ECB_No;
// Set as root component
RootComponent = CollisionComp;
// Use a ProjectileMovementComponent to govern this projectile's movement
ProjectileMovement = CreateDefaultSubobject<UProjectileMovementComponent>(TEXT("ProjectileComp"));
ProjectileMovement->UpdatedComponent = CollisionComp;
ProjectileMovement->InitialSpeed = 3000.f;
ProjectileMovement->MaxSpeed = 3000.f;
ProjectileMovement->bRotationFollowsVelocity = true;
ProjectileMovement->bShouldBounce = true;
// Die after 3 seconds by default
InitialLifeSpan = 3.0f;
}
void AEndlessVendettaProjectile::OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
// Only add impulse and destroy projectile if we hit a physics
if ((OtherActor != nullptr) && (OtherActor != this) && (OtherComp != nullptr) && OtherComp->IsSimulatingPhysics())
{
OtherComp->AddImpulseAtLocation(GetVelocity() * 100.0f, GetActorLocation());
Destroy();
}
}

View File

@ -1,37 +0,0 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "EndlessVendettaProjectile.generated.h"
class USphereComponent;
class UProjectileMovementComponent;
UCLASS(config=Game)
class AEndlessVendettaProjectile : public AActor
{
GENERATED_BODY()
/** Sphere collision component */
UPROPERTY(VisibleDefaultsOnly, Category=Projectile)
USphereComponent* CollisionComp;
/** Projectile movement component */
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Movement, meta = (AllowPrivateAccess = "true"))
UProjectileMovementComponent* ProjectileMovement;
public:
AEndlessVendettaProjectile();
/** called when projectile hits something */
UFUNCTION()
void OnHit(UPrimitiveComponent* HitComp, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
/** Returns CollisionComp subobject **/
USphereComponent* GetCollisionComp() const { return CollisionComp; }
/** Returns ProjectileMovement subobject **/
UProjectileMovementComponent* GetProjectileMovement() const { return ProjectileMovement; }
};

View File

@ -1,31 +0,0 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "TP_PickUpComponent.h"
UTP_PickUpComponent::UTP_PickUpComponent()
{
// Setup the Sphere Collision
SphereRadius = 32.f;
}
void UTP_PickUpComponent::BeginPlay()
{
Super::BeginPlay();
// Register our Overlap Event
OnComponentBeginOverlap.AddDynamic(this, &UTP_PickUpComponent::OnSphereBeginOverlap);
}
void UTP_PickUpComponent::OnSphereBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
// Checking if it is a First Person Character overlapping
AEndlessVendettaCharacter* Character = Cast<AEndlessVendettaCharacter>(OtherActor);
if(Character != nullptr)
{
// Notify that the actor is being picked up
OnPickUp.Broadcast(Character);
// Unregister from the Overlap Event so it is no longer triggered
OnComponentBeginOverlap.RemoveAll(this);
}
}

View File

@ -1,34 +0,0 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Components/SphereComponent.h"
#include "EndlessVendetta/EndlessVendettaCharacter.h"
#include "TP_PickUpComponent.generated.h"
// Declaration of the delegate that will be called when someone picks this up
// The character picking this up is the parameter sent with the notification
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnPickUp, AEndlessVendettaCharacter*, PickUpCharacter);
UCLASS(Blueprintable, BlueprintType, ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class ENDLESSVENDETTA_API UTP_PickUpComponent : public USphereComponent
{
GENERATED_BODY()
public:
/** Delegate to whom anyone can subscribe to receive this event */
UPROPERTY(BlueprintAssignable, Category = "Interaction")
FOnPickUp OnPickUp;
UTP_PickUpComponent();
protected:
/** Called when the game starts */
virtual void BeginPlay() override;
/** Code for when something overlaps this component */
UFUNCTION()
void OnSphereBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);
};

View File

@ -1,112 +0,0 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#include "TP_WeaponComponent.h"
#include "EndlessVendetta/EndlessVendettaCharacter.h"
#include "EndlessVendettaProjectile.h"
#include "GameFramework/PlayerController.h"
#include "Camera/PlayerCameraManager.h"
#include "Kismet/GameplayStatics.h"
#include "EnhancedInputComponent.h"
#include "EnhancedInputSubsystems.h"
// Sets default values for this component's properties
UTP_WeaponComponent::UTP_WeaponComponent()
{
// Default offset from the character location for projectiles to spawn
MuzzleOffset = FVector(100.0f, 0.0f, 10.0f);
}
void UTP_WeaponComponent::Fire()
{
if (Character == nullptr || Character->GetController() == nullptr)
{
return;
}
// Try and fire a projectile
if (ProjectileClass != nullptr)
{
UWorld* const World = GetWorld();
if (World != nullptr)
{
APlayerController* PlayerController = Cast<APlayerController>(Character->GetController());
const FRotator SpawnRotation = PlayerController->PlayerCameraManager->GetCameraRotation();
// MuzzleOffset is in camera space, so transform it to world space before offsetting from the character location to find the final muzzle position
const FVector SpawnLocation = GetOwner()->GetActorLocation() + SpawnRotation.RotateVector(MuzzleOffset);
//Set Spawn Collision Handling Override
FActorSpawnParameters ActorSpawnParams;
ActorSpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AdjustIfPossibleButDontSpawnIfColliding;
// Spawn the projectile at the muzzle
World->SpawnActor<AEndlessVendettaProjectile>(ProjectileClass, SpawnLocation, SpawnRotation, ActorSpawnParams);
}
}
// Try and play the sound if specified
if (FireSound != nullptr)
{
UGameplayStatics::PlaySoundAtLocation(this, FireSound, Character->GetActorLocation());
}
// Try and play a firing animation if specified
if (FireAnimation != nullptr)
{
// Get the animation object for the arms mesh
UAnimInstance* AnimInstance = Character->GetMesh1P()->GetAnimInstance();
if (AnimInstance != nullptr)
{
AnimInstance->Montage_Play(FireAnimation, 1.f);
}
}
}
void UTP_WeaponComponent::AttachWeapon(AEndlessVendettaCharacter* TargetCharacter)
{
Character = TargetCharacter;
if (Character == nullptr)
{
return;
}
// Attach the weapon to the First Person Character
FAttachmentTransformRules AttachmentRules(EAttachmentRule::SnapToTarget, true);
AttachToComponent(Character->GetMesh1P(), AttachmentRules, FName(TEXT("GripPoint")));
// switch bHasRifle so the animation blueprint can switch to another animation set
Character->SetHasRifle(true);
// Set up action bindings
if (APlayerController* PlayerController = Cast<APlayerController>(Character->GetController()))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
// Set the priority of the mapping to 1, so that it overrides the Jump action with the Fire action when using touch input
Subsystem->AddMappingContext(FireMappingContext, 1);
}
if (UEnhancedInputComponent* EnhancedInputComponent = Cast<UEnhancedInputComponent>(PlayerController->InputComponent))
{
// Fire
EnhancedInputComponent->BindAction(FireAction, ETriggerEvent::Triggered, this, &UTP_WeaponComponent::Fire);
}
}
}
void UTP_WeaponComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
if (Character == nullptr)
{
return;
}
if (APlayerController* PlayerController = Cast<APlayerController>(Character->GetController()))
{
if (UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PlayerController->GetLocalPlayer()))
{
Subsystem->RemoveMappingContext(FireMappingContext);
}
}
}

View File

@ -1,60 +0,0 @@
// Copyright Epic Games, Inc. All Rights Reserved.
#pragma once
#include "CoreMinimal.h"
#include "Components/SkeletalMeshComponent.h"
#include "TP_WeaponComponent.generated.h"
class AEndlessVendettaCharacter;
UCLASS(Blueprintable, BlueprintType, ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ENDLESSVENDETTA_API UTP_WeaponComponent : public USkeletalMeshComponent
{
GENERATED_BODY()
public:
/** Projectile class to spawn */
UPROPERTY(EditDefaultsOnly, Category=Projectile)
TSubclassOf<class AEndlessVendettaProjectile> ProjectileClass;
/** Sound to play each time we fire */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
USoundBase* FireSound;
/** AnimMontage to play each time we fire */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = Gameplay)
UAnimMontage* FireAnimation;
/** Gun muzzle's offset from the characters location */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Gameplay)
FVector MuzzleOffset;
/** MappingContext */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputMappingContext* FireMappingContext;
/** Fire Input Action */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category=Input, meta=(AllowPrivateAccess = "true"))
class UInputAction* FireAction;
/** Sets default values for this component's properties */
UTP_WeaponComponent();
/** Attaches the actor to a FirstPersonCharacter */
UFUNCTION(BlueprintCallable, Category="Weapon")
void AttachWeapon(AEndlessVendettaCharacter* TargetCharacter);
/** Make the weapon Fire a Projectile */
UFUNCTION(BlueprintCallable, Category="Weapon")
void Fire();
protected:
/** Ends gameplay for this component. */
UFUNCTION()
virtual void EndPlay(const EEndPlayReason::Type EndPlayReason) override;
private:
/** The Character holding this weapon*/
AEndlessVendettaCharacter* Character;
};