For this project, I have used the UE4 SHOOTER-GAME sample as a template.
I have been able to get not only have a grenade spawn in the correct location in front of the Player using Blueprint, but also travel in the respective forwards direction (no matter where the Player is looking and following the intended mechanics for such (based off the Halo plasma-grenade, exploding after 3 seconds from hitting a target, bouncing off entities that are not Players whilst sticking to Players when impacting them).
I have attempted to implement such functionality in C++, creating a custom class (ProjPlasmaGrenade), to handle this and I am unable to test out the other functionality of the grenade, aside from spawning, as it won’t spawn in the intended location (in front of where the Player is looking).
In the above image, is the PlayerPawn Blueprint, with a sphere component selected for where the grenades should spawn relative to the Player’s pawn (near the end of their rifle in this preview).
In the image below, is the ProjPlasmaGrenade Blueprint for the plasma-grenade, with the Body (main visual) component selected (it is the child of the collision sphere):
’
Just below, is a screenshot of the Player holding the plasma-grenade, as intended (1st-person perspective):
Next, is the collision-component of the plasma-grenade (the root-component), for where it should spawn in the world:
Next comes the Body component of the plasma-grenade, quite far away from the root-component and under a static-mesh of the level construct:
I have also included the method that spawns a grenade, into the game world just below:
void AShooterWeapon_Projectile::SpawnGrenade()
{
// Get a reference to the Player pawn:
AShooterCharacter* WeaponOwner = GetPawnOwner();
// To hold the camera manager actor (there is only one):
TArray<AActor*> CameraManagerActor;
UGameplayStatics::GetAllActorsOfClass(this, APlayerCameraManager::StaticClass(), CameraManagerActor);
CameraManagerReference = Cast<AShooterPlayerCameraManager>(CameraManagerActor[0]);
FRotator CameraRotation;
if (CameraManagerReference)
{
CameraRotation = CameraManagerReference->GetActorTransformComponentTransform().GetRotation().Rotator();
}
// To offset the placement in the correct direction:
FVector RotatedOffset = CameraRotation.RotateVector(GrenadeSpawnOffset);
FVector SpawnLocation = WeaponOwner->GrenadeSpawnPoint->GetComponentLocation();
FTransform SpawnTransform = FTransform(RotatedOffset.Rotation(), SpawnLocation, DefaultSpawnScale);
SpawnedPlasmaGrenade = Cast<AProjPlasmaGrenade>(UGameplayStatics::BeginSpawningActorFromBlueprint(this, ProjectileBlueprint, SpawnTransform, false));
if (SpawnedPlasmaGrenade)
{
SetActorHiddenInGame(true);
UGameplayStatics::FinishSpawningActor(SpawnedPlasmaGrenade, SpawnTransform);
// To prevent it being cleaned up here too:
SpawnedPlasmaGrenade->SetFlags(EObjectFlags::RF_MarkAsRootSet);
}
}
For added clarity, what I believe are the key classes related to this issue, are shown below:
ShooterWeapon_Projectile.h
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "ShooterWeapon.h"
#include "GameFramework/DamageType.h" // for UDamageType::StaticClass()
#include "ShooterWeapon_Projectile.generated.h"
USTRUCT()
struct FProjectileWeaponData
{
GENERATED_USTRUCT_BODY()
/** projectile class */
UPROPERTY(EditDefaultsOnly, Category=Projectile)
TSubclassOf<class AShooterProjectile> ProjectileClass;
/** life time */
UPROPERTY(EditDefaultsOnly, Category=Projectile)
float ProjectileLife;
/** damage at impact point */
UPROPERTY(EditDefaultsOnly, Category=WeaponStat)
int32 ExplosionDamage;
/** radius of damage */
UPROPERTY(EditDefaultsOnly, Category=WeaponStat)
float ExplosionRadius;
/** type of damage */
UPROPERTY(EditDefaultsOnly, Category=WeaponStat)
TSubclassOf<UDamageType> DamageType;
/** defaults */
FProjectileWeaponData()
{
ProjectileClass = NULL;
ProjectileLife = 10.0f;
ExplosionDamage = 100;
ExplosionRadius = 300.0f;
DamageType = UDamageType::StaticClass();
}
};
// A weapon that fires a visible projectile
UCLASS(Abstract)
class AShooterWeapon_Projectile : public AShooterWeapon
{
GENERATED_UCLASS_BODY()
/** apply config on projectile */
void ApplyWeaponConfig(FProjectileWeaponData& Data);
protected:
/** weapon config */
UPROPERTY(EditDefaultsOnly, Category=Config)
FProjectileWeaponData ProjectileConfig;
/** Weapons that are not rocket weapons are to be handled differently. */
UPROPERTY(EditDefaultsOnly, Category = Flags)
bool IsCustomWeapon;
/** For the transformation of certain projectile weapons. */
FTransform CustomProjectileTransformation;
//(X = 70.000000, Y = 0.000000, Z = 80.000000)
public:
// Constant Values:
/** For the plasma grenade weapon. */
// Tried spawning the grenades at a socket on the skeltal mesh,
// but this would not spawn the grenades where it would make sense to.
const FName GRENADE_SPAWN_POINT = FName("GrenadePoint");
// For the name of the plasma grenade, to identify it:
const FName PLASMA_GRENADE_ID = FName("PlasmaGrenade");
// Custom lifetime after impact, after which, it will explode:
const float PLASMA_GRENADE_FUSE_TIME_AFTER_IMPACT = 3000.0f;
// For a tag used to identify a sphere used to spawn the grenades at:
const FName DEFAULT_PROJECTILE_SPAWN_POINT = FName("ProjectileSpawnPoint");
// Plasma grenade usage:
/**
* For whether the Player can spawn this grenade or not
* (can only use the plasma grenade weapon if the spawned
* plasma grenade is invalid).
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WeaponManagement)
class AProjPlasmaGrenade* SpawnedPlasmaGrenade;
/** The default scale to use when spawning the plasma grenade into the level. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WeaponManagement)
FVector DefaultSpawnScale;
/** For use in spawning the grenade at the correct position. */
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WeaponManagement)
class AShooterPlayerCameraManager* CameraManagerReference;
/** For use in spawning grenades or other throwable projectiles. */
UPROPERTY(EditDefaultsOnly, Category = Projectile)
UBlueprint* ProjectileBlueprint;
/**
* To clean up the plasma grenade pointer of this class
* (so grenades can be spawned again).
*/
void DestroyGrenade();
/**
* For suitable off-setting the spawn point of the grenade from the weapon
* (so that spawning the grenade will not fail).
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = WeaponManagement)
FVector GrenadeSpawnOffset;
protected:
//////////////////////////////////////////////////////////////////////////
// Weapon usage
/** To handle spawning the grenade. */
void SpawnGrenade();
/**
* [local] weapon specific fire implementation
*
*/
virtual void FireWeapon(FTransform TargetProjectileSpawnTransformation) override;
/** For plasma grenades. */
void HandleGrenadeThrowing();
/** spawn projectile on server */
UFUNCTION(reliable, server, WithValidation)
void ServerFireProjectile(FVector Origin, FVector_NetQuantizeNormal ShootDir);
};
ShooterWeapon_Projectile.cpp
// Copyright 1998-2017 Epic Games, Inc. All Rights Reserved.
#include "ShooterGame.h"
#include "Weapons/ShooterWeapon_Projectile.h"
#include "Player/ShooterPlayerCameraManager.h"
#include "Player/ShooterCharacter.h"
#include "ProjPlasmaGrenade.h"
//#include ""
#include "Weapons/ShooterProjectile.h"
AShooterWeapon_Projectile::AShooterWeapon_Projectile(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
// For the plasma grenade:
DefaultSpawnScale = FVector(0.25f, 0.25f, 0.25f);
GrenadeSpawnOffset = FVector(100.0f, 0.0f, -10.0f);
}
//////////////////////////////////////////////////////////////////////////
// Weapon usage
void AShooterWeapon_Projectile::FireWeapon(FTransform TargetProjectileSpawnTransformation)
{
// In a previous attempt to spawn the plasma grenade at the correct location:
CustomProjectileTransformation = TargetProjectileSpawnTransformation;
// For plasma-grenades:
if (IsCustomWeapon && WeaponConfig.WeaponName == PLASMA_GRENADE_ID)
{
HandleGrenadeThrowing();
return;
}
FVector ShootDir = GetAdjustedAim();
FVector Origin = GetMuzzleLocation();
// trace from camera to check what's under crosshair
const float ProjectileAdjustRange = 10000.0f;
const FVector StartTrace = GetCameraDamageStartLocation(ShootDir);
const FVector EndTrace = StartTrace + ShootDir * ProjectileAdjustRange;
FHitResult Impact = WeaponTrace(StartTrace, EndTrace);
// and adjust directions to hit that actor
if (Impact.bBlockingHit)
{
const FVector AdjustedDir = (Impact.ImpactPoint - Origin).GetSafeNormal();
bool bWeaponPenetration = false;
const float DirectionDot = FVector::DotProduct(AdjustedDir, ShootDir);
if (DirectionDot < 0.0f)
{
// shooting backwards = weapon is penetrating
bWeaponPenetration = true;
}
else if (DirectionDot < 0.5f)
{
// check for weapon penetration if angle difference is big enough
// raycast along weapon mesh to check if there's blocking hit
FVector MuzzleStartTrace = Origin - GetMuzzleDirection() * 150.0f;
FVector MuzzleEndTrace = Origin;
FHitResult MuzzleImpact = WeaponTrace(MuzzleStartTrace, MuzzleEndTrace);
if (MuzzleImpact.bBlockingHit)
{
bWeaponPenetration = true;
}
}
// This is considered to be true (1) for grenades being instantiated:
if (bWeaponPenetration && !IsCustomWeapon)
{
// spawn at crosshair position
Origin = Impact.ImpactPoint - ShootDir * 10.0f;
}
else
{
// adjust direction to hit
ShootDir = AdjustedDir;
}
}
ServerFireProjectile(Origin, ShootDir);
}
// This custom method was implemented for handling the grenades being thrown (different than for other projectiles):
void AShooterWeapon_Projectile::HandleGrenadeThrowing()
{
if (!SpawnedPlasmaGrenade)
{
SpawnGrenade();
}
}
void AShooterWeapon_Projectile::DestroyGrenade()
{
if (SpawnedPlasmaGrenade)
{
//SpawnedPlasmaGrenade->ConditionalBeginDestroy();
}
}
void AShooterWeapon_Projectile::SpawnGrenade()
{
// Get a reference to the Player pawn:
AShooterCharacter* WeaponOwner = GetPawnOwner();
// To hold the camera manager actor (there is only one):
TArray<AActor*> CameraManagerActor;
UGameplayStatics::GetAllActorsOfClass(this, APlayerCameraManager::StaticClass(), CameraManagerActor);
CameraManagerReference = Cast<AShooterPlayerCameraManager>(CameraManagerActor[0]);
FRotator CameraRotation;
if (CameraManagerReference)
{
CameraRotation = CameraManagerReference->GetActorTransformComponentTransform().GetRotation().Rotator();
}
// To offset the placement in the correct direction:
FVector RotatedOffset = CameraRotation.RotateVector(GrenadeSpawnOffset);
FVector SpawnLocation = WeaponOwner->GrenadeSpawnPoint->GetComponentLocation();
FTransform SpawnTransform = FTransform(RotatedOffset.Rotation(), SpawnLocation, DefaultSpawnScale);
SpawnedPlasmaGrenade = Cast<AProjPlasmaGrenade>(UGameplayStatics::BeginSpawningActorFromBlueprint(this, ProjectileBlueprint, SpawnTransform, false));
if (SpawnedPlasmaGrenade)
{
SetActorHiddenInGame(true);
UGameplayStatics::FinishSpawningActor(SpawnedPlasmaGrenade, SpawnTransform);
// To prevent it being cleaned up here too:
SpawnedPlasmaGrenade->SetFlags(EObjectFlags::RF_MarkAsRootSet);
}
}
bool AShooterWeapon_Projectile::ServerFireProjectile_Validate(FVector Origin, FVector_NetQuantizeNormal ShootDir)
{
return true;
}
void AShooterWeapon_Projectile::ServerFireProjectile_Implementation(FVector Origin, FVector_NetQuantizeNormal ShootDir)
{
FTransform SpawnTM(ShootDir.Rotation(), Origin);
AShooterProjectile* Projectile = Cast<AShooterProjectile>(UGameplayStatics::BeginDeferredActorSpawnFromClass(this, ProjectileConfig.ProjectileClass, SpawnTM));
if (Projectile)
{
Projectile->Instigator = Instigator;
Projectile->SetOwner(this);
Projectile->InitVelocity(ShootDir);
UGameplayStatics::FinishSpawningActor(Projectile, SpawnTM);
}
}
void AShooterWeapon_Projectile::ApplyWeaponConfig(FProjectileWeaponData& Data)
{
Data = ProjectileConfig;
}
/**
REFERENCE.
*/
//AShooterCharacter* OwnerCharacter = GetPawnOwner();
//UStaticMeshComponent* GrenadeSpawnLocationReference = Cast<UStaticMeshComponent>(OwnerCharacter->GetComponentByClass(UStaticMeshComponent::StaticClass()));
//USkeletalMeshComponent* FirstPersonMeshReference = GetPawnOwner()->GetPawnMesh();
//if (ProjectileConfig.ProjectileClass && FirstPersonMeshReference)
//{
// // SOLVE ISSUE HERE
//
// // Not quite, adjust this to spawn the projectile for the character's facing
// FVector TargetPosition = FirstPersonMeshReference->GetSocketLocation(GRENADE_SPAWN_POINT) + OwnerCharacter->GetActorForwardVector();
// FTransform SpawnTransform = FTransform(GrenadeSpawnLocationReference->GetComponentToWorld());
// AShooterProjectile* GrenadeProjectile = Cast<AShooterProjectile>(UGameplayStatics::BeginDeferredActorSpawnFromClass(
// this, ProjectileConfig.ProjectileClass, SpawnTransform));
// if (GrenadeProjectile)
// {
// GrenadeProjectile->Instigator = Instigator;
// GrenadeProjectile->SetOwner(this);
//
// UGameplayStatics::FinishSpawningActor(GrenadeProjectile, SpawnTransform);
// }
//}
ProjPlasmaGrenade.h
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "ProjPlasmaGrenade.generated.h"
USTRUCT()
struct FThrowableWeaponData
{
GENERATED_USTRUCT_BODY()
/** The damage dealt by this weapon in the base damage radius. */
UPROPERTY(EditDefaultsOnly, Category = ThrowableProjectile)
float BaseDamage;
/** The minimum possible damage out to MaximumDamageRadius. */
UPROPERTY(EditDefaultsOnly, Category = ThrowableProjectile)
float MinimumDamage;
/** The base damage dealt to actors out to this value, from the origin (no falloff). */
UPROPERTY(EditDefaultsOnly, Category = ThrowableProjectile)
float BaseDamageRadius;
/** The base damage factoring in the damage falloff, is dealt to actors out to this value, from the origin. */
UPROPERTY(EditDefaultsOnly, Category = ThrowableProjectile)
float MaximumDamageRadius;
/** Damage outside the base damage radius, is scaled by this value up to the maximum damage radius. */
UPROPERTY(EditDefaultsOnly, Category = ThrowableProjectile)
float DamageFalloff;
// For default values:
FThrowableWeaponData()
{
BaseDamage = 100.0f;
MinimumDamage = 5.0f;
BaseDamageRadius = 396.0f;
MaximumDamageRadius = 1290.0f;
DamageFalloff = 0.1f;
}
};
UCLASS()
class SHOOTERGAME_API AProjPlasmaGrenade : public AActor
{
GENERATED_BODY()
public:
/** Set-up this projectile. */
AProjPlasmaGrenade(const FObjectInitializer& ObjectInitializer);
/** For the main visible component of this projectile. */
UPROPERTY(EditDefaultsOnly, Category = VisualComponent)
UStaticMeshComponent* Body;
/** To handle this actor's movement, as a projectile. */
UPROPERTY(EditDefaultsOnly, Category = Movement)
UProjectileMovementComponent* MovementComponent;
/** For the explosion effect to show in the game world. */
UPROPERTY(EditDefaultsOnly, Category = GraphicsEffects)
UParticleSystem* ExplosionParticleSystem;
/** For the sound cue to play in the game world. */
UPROPERTY(EditDefaultsOnly, Category = SoundEffects)
USoundCue* ExplosionSoundCue;
UPROPERTY(EditDefaultsOnly, Category = Data)
FThrowableWeaponData GrenadeWeaponData;
UPROPERTY(EditDefaultsOnly, Category = Type)
class TSubclassOf<UDamageType> GrenadeDamageType;
UPROPERTY(EditDefaultsOnly, Category = VisualComponent)
UMaterialInterface* DefaultBodyMaterial;
/** To handle collision. */
UPROPERTY(EditDefaultsOnly, Category = Collision)
USphereComponent* CollisionComponent;
protected:
// Functions:
/** For when a component gets hit. */
UFUNCTION(BlueprintCallable, Category = Collision)
void OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit);
/** For when this actor gets hit. */
UFUNCTION(BlueprintCallable, Category = Collision)
void ActorHit(AActor* SelfActor, AActor* OtherActor, FVector NormalImpulse, const FHitResult& Hit);
/** For the detonation sequence */
void InitiateDetonationSequence(AActor* HitActor, UPrimitiveComponent* ComponentHit);
void DetermineTargetHit(AActor* TargetActor);
void HandleExplosion();
void ShowEffects(USceneComponent* TargetComponent);
void HandleDamage(USceneComponent* TargetComponent);
void HideComponent(USceneComponent* TargetComponent);
// Properties of this projectile:
/** The time in seconds, until the grenade explodes. */
float GrenadeLifespanAfterCollision;
/** The detonation sequence can only be initiated once. */
bool DetonationSequenceInitiated;
/** The time to see the explosion, before this actor is destroyed. */
float TimeToSeeExplosion;
/** The pawn that was hit. */
class AShooterCharacter* HitPawn;
/** To let the Player know when the grenade has been removed from play. */
ACharacter* PlayerCharacterReference;
// Constant values:
const FName ACTOR_HIT_METHOD_NAME = "ActorHit";
};
ProjPlasmaGrenade.cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "ShooterGame.h"
#include "ProjPlasmaGrenade.h"
#include "ShooterCharacter.h"
#include "ShooterWeapon_Projectile.h"
#include "ShooterBot.h"
// Initialise:
AProjPlasmaGrenade::AProjPlasmaGrenade(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
// To stop tGC cleaning this up prematurly:
SetFlags(EObjectFlags::RF_MarkAsRootSet);
CollisionComponent = ObjectInitializer.CreateDefaultSubobject<USphereComponent>(this, TEXT("CollisionComponent"));
CollisionComponent->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
CollisionComponent->InitSphereRadius(5.0f);
CollisionComponent->AlwaysLoadOnClient = true;
CollisionComponent->AlwaysLoadOnServer = true;
CollisionComponent->bTraceComplexOnMove = true;
CollisionComponent->SetCollisionEnabled(ECollisionEnabled::QueryOnly);
CollisionComponent->SetNotifyRigidBodyCollision(true);
CollisionComponent->SetCollisionObjectType(COLLISION_PROJECTILE);
CollisionComponent->SetCollisionResponseToAllChannels(ECR_Ignore);
CollisionComponent->SetCollisionResponseToChannel(ECC_WorldStatic, ECR_Block);
CollisionComponent->SetCollisionResponseToChannel(ECC_WorldDynamic, ECR_Block);
CollisionComponent->SetCollisionResponseToChannel(ECC_Pawn, ECR_Block);
CollisionComponent->OnComponentHit.AddDynamic(this, &AProjPlasmaGrenade::OnComponentHit);
SetRootComponent(CollisionComponent);
Body = ObjectInitializer.CreateDefaultSubobject<UStaticMeshComponent>(this, TEXT("Body"));
Body->OverrideMaterials.Add(DefaultBodyMaterial);
Body->SetMaterial(0, DefaultBodyMaterial);
MovementComponent = ObjectInitializer.CreateDefaultSubobject<UProjectileMovementComponent>(this, TEXT("MovementComponent"));
MovementComponent->InitialSpeed = 3000.0f;
MovementComponent->MaxSpeed = 3000.0f;
MovementComponent->bShouldBounce = true;
MovementComponent->bBounceAngleAffectsFriction = true;
MovementComponent->Bounciness = 0.6f;
MovementComponent->Friction = 0.2f;
MovementComponent->BounceVelocityStopSimulatingThreshold = 5.0f;
MovementComponent->Velocity = FVector(3000.0f, 0.0f, 0.0f);
// When created, have the grenade be thrown away from the thrower:
MovementComponent->SetAutoActivate(true);
PlayerCharacterReference = UGameplayStatics::GetPlayerCharacter(this, 0);
}
void AProjPlasmaGrenade::OnComponentHit(UPrimitiveComponent* HitComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, FVector NormalImpulse, const FHitResult& Hit)
{
if (!DetonationSequenceInitiated && GetWorld()->HasBegunPlay() && PlayerCharacterReference)
{
DetonationSequenceInitiated = true;
InitiateDetonationSequence(OtherActor, OtherComp);
}
}
void AProjPlasmaGrenade::ActorHit(AActor* SelfActor, AActor* OtherActor, FVector NormalImpulse, const FHitResult& Hit)
{
if (!DetonationSequenceInitiated && GetWorld()->HasBegunPlay() && PlayerCharacterReference)
{
DetonationSequenceInitiated = true;
InitiateDetonationSequence(OtherActor, Hit.GetComponent());
}
}
void AProjPlasmaGrenade::InitiateDetonationSequence(AActor* HitActor, UPrimitiveComponent* ComponentHit)
{
DetermineTargetHit(HitActor);
if (HitPawn)
{
MovementComponent->StopMovementImmediately();
// Attach this to the component of the pawn that was hit:
AttachToComponent(ComponentHit, FAttachmentTransformRules(EAttachmentRule::KeepWorld,
EAttachmentRule::KeepWorld, EAttachmentRule::KeepWorld, true));
Body->SetCollisionEnabled(ECollisionEnabled::Type::NoCollision);
}
FTimerHandle TimerHandle = FTimerHandle();
// Initiate the fuse countdown:
GetWorldTimerManager().SetTimer(TimerHandle, GrenadeLifespanAfterCollision, false);
HideComponent(Body);
HandleExplosion();
// Give Players time to see the explosion effect:
GetWorldTimerManager().SetTimer(TimerHandle, TimeToSeeExplosion, false);
Cast<AShooterCharacter>(PlayerCharacterReference)->GrenadeRemovedFromPlay();
Cast<AShooterWeapon_Projectile>(Cast<AShooterCharacter>(PlayerCharacterReference)->GetWeapon())->DestroyGrenade();
}
void AProjPlasmaGrenade::DetermineTargetHit(AActor* TargetActor)
{
HitPawn = Cast<AShooterBot>(TargetActor);
// A shooter bot was hit:
if (HitPawn) return;
HitPawn = Cast<AShooterCharacter>(TargetActor);
// The Player was hit:
if (HitPawn) return;
// Something else was hit:
HitPawn = nullptr;
}
void AProjPlasmaGrenade::HandleExplosion()
{
USceneComponent* TargetComponent;
if (HitPawn)
{
TargetComponent = HitPawn->GetMesh();
}
else
{
TargetComponent = Body;
HideComponent(TargetComponent);
}
ShowEffects(TargetComponent);
HandleDamage(TargetComponent);
}
void AProjPlasmaGrenade::ShowEffects(USceneComponent* TargetComponent)
{
// Make sure to keep the explosion's world scale:
UGameplayStatics::SpawnEmitterAttached(ExplosionParticleSystem, TargetComponent);
UGameplayStatics::SpawnSoundAttached(ExplosionSoundCue, TargetComponent);
}
void AProjPlasmaGrenade::HandleDamage(USceneComponent* TargetComponent)
{
TArray<AActor*> ActorsToIgnore;
UGameplayStatics::ApplyRadialDamageWithFalloff(this, GrenadeWeaponData.BaseDamage, GrenadeWeaponData.MinimumDamage,
TargetComponent->GetComponentLocation(), GrenadeWeaponData.BaseDamageRadius, GrenadeWeaponData.MaximumDamageRadius,
GrenadeWeaponData.DamageFalloff, GrenadeDamageType, ActorsToIgnore, this, PlayerCharacterReference->GetController(),
ECollisionChannel::ECC_Visibility);
}
void AProjPlasmaGrenade::HideComponent(USceneComponent* TargetComponent)
{
TargetComponent->SetVisibility(false);
}
Please let me know what is/may be causing this issue and also let me know if there is any additional information that would help in solving this issue, my thanks to you all.