Had a similar problem with my RadialDamageComponent. I tried to visualize (editor only) the damaging area using USphereComponent. For me helped to move debug sphere creation from OnRegister to CTOR and using CreateEditorOnlyDefaultSubobject() instead of NewObject. I hope it helps you too.
RadialDamageComponent.h
#pragma once
#include "CoreMinimal.h"
#include "Components/SceneComponent.h"
#include "UObject/SparseDelegate.h"
#include "RadialDamageComponent.generated.h"
class URadialDamageComponent;
DECLARE_DYNAMIC_MULTICAST_SPARSE_DELEGATE_OneParam(
FRadialDamageComponentAppliedDamageSignature, URadialDamageComponent, OnRadialDamageApplied, URadialDamageComponent*, Component);
UCLASS( ClassGroup=(Damaging), meta=(BlueprintSpawnableComponent) )
class TANKSVR_API URadialDamageComponent : public USceneComponent
{
GENERATED_BODY()
public:
URadialDamageComponent(const FObjectInitializer& ObjectInitializer);
virtual void BeginPlay() override;
virtual void EndPlay(EEndPlayReason::Type EndPlayReason) override;
virtual void TickComponent(float DeltaTime, enum ELevelTick TickType, FActorComponentTickFunction *ThisTickFunction) override;
virtual void OnRegister() override;
virtual void OnComponentDestroyed(bool bDestroyingHierarchy) override;
UFUNCTION()
void OnOwnerTookAnyDamage(AActor* DamagedActor, float Damage, const class UDamageType* DamageType, class AController* InstigatedBy, AActor* DamageCauser);
#if WITH_EDITOR
virtual void CheckForErrors() override;
#endif
#if WITH_EDITORONLY_DATA
static void AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector);
virtual void PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent) override;
virtual void RefreshVisualRepresentation();
#endif
private:
void Validate_OwnerCanBeDamaged() const;
FString GetErrorMsg_OwnerCanBeDamaged() const;
public:
UPROPERTY(BlueprintAssignable, Category = "Components|RadialDamageComponent")
FRadialDamageComponentAppliedDamageSignature OnRadialDamageApplied;
protected:
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(UIMin=0, ClampMin="0"), Category=Options)
float DamageValue = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta=(UIMin=0, ClampMin="0"), Category=Options)
float DamageRadius = 100;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=Options)
TSubclassOf<UDamageType> DamageTypeClass;
private:
#if WITH_EDITORONLY_DATA
class USphereComponent* DamageRadiusDebugSphere = nullptr;
#endif
};
RadialDamageComponent.cpp
#include "RadialDamageComponent.h"
#include "DrawDebugHelpers.h"
#include "Components/SphereComponent.h"
#include "Kismet/GameplayStatics.h"
#include "Logging/MessageLog.h"
#include "Misc/UObjectToken.h"
#include "TanksVr/TanksVrCheatSheet.h"
#include "TanksVr/TanksVr.h"
static int32 GShowDebugSphere = 0;
FAutoConsoleVariableRef CVarDebug(
TanksVrCheatSheet::RadialDamageComponent_ShowDebugSphere, GShowDebugSphere,
TanksVrCheatSheet::RadialDamageComponent_ShowDebugSphere_Description, ECVF_Cheat);
URadialDamageComponent::URadialDamageComponent(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
PrimaryComponentTick.bCanEverTick = true;
PrimaryComponentTick.SetTickFunctionEnable(true);
bAutoActivate = true;
DamageRadiusDebugSphere = ObjectInitializer.CreateEditorOnlyDefaultSubobject<USphereComponent>(this, TEXT("DamageRadiusSphere_EditorOnly"));
DamageRadiusDebugSphere->SetupAttachment(this);
DamageRadiusDebugSphere->SetIsVisualizationComponent(true);
DamageRadiusDebugSphere->SetCollisionProfileName(UCollisionProfile::NoCollision_ProfileName);
DamageRadiusDebugSphere->CreationMethod = CreationMethod;
DamageRadiusDebugSphere->CastShadow = false;
}
void URadialDamageComponent::BeginPlay()
{
Super::BeginPlay();
if (GetOwnerRole() == ROLE_Authority)
{
GetOwner()->OnTakeAnyDamage.AddDynamic(this, &URadialDamageComponent::OnOwnerTookAnyDamage);
}
}
void URadialDamageComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
GetOwner()->OnTakeAnyDamage.RemoveDynamic(this, &URadialDamageComponent::OnOwnerTookAnyDamage);
Super::EndPlay(EndPlayReason);
}
void URadialDamageComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
if (GShowDebugSphere)
{
DrawDebugSphere(GetWorld(), GetComponentLocation(), DamageRadius, 12, FColor::Red);
}
}
void URadialDamageComponent::OnOwnerTookAnyDamage(AActor* DamagedActor, float Damage, const UDamageType* DamageType,
AController* InstigatedBy, AActor* DamageCauser)
{
ensure(DamagedActor == GetOwner());
ensure(GetOwnerRole() == ROLE_Authority);
UE_LOG(TanksVR, Log, TEXT("%s received damage. Apply self radial damage %f at %s] with radius %f"),
*GetOwner()->GetName(), DamageValue, *GetComponentLocation().ToString(), DamageRadius);
// TODO: Check Damage value
// TODO: Here might be check for out health component. For now assume this object takes one damage to do own damage
UGameplayStatics::ApplyRadialDamage(this, DamageValue, GetComponentLocation(),
DamageRadius, DamageTypeClass, TArray<AActor*>(), GetOwner(), InstigatedBy, true);
OnRadialDamageApplied.Broadcast(this);
}
#if WITH_EDITOR
void URadialDamageComponent::CheckForErrors()
{
Super::CheckForErrors();
const auto Owner = GetOwner();
if (Owner && !Owner->CanBeDamaged())
{
FMessageLog("MapCheck")
.Warning()
->AddToken(FUObjectToken::Create(Owner))
->AddToken(FTextToken::Create(FText::FromString(GetErrorMsg_OwnerCanBeDamaged())));
}
}
#endif
void URadialDamageComponent::OnRegister()
{
#if WITH_EDITORONLY_DATA
{
Validate_OwnerCanBeDamaged();
RefreshVisualRepresentation();
}
#endif
Super::OnRegister();
}
void URadialDamageComponent::OnComponentDestroyed(const bool bDestroyingHierarchy)
{
Super::OnComponentDestroyed(bDestroyingHierarchy);
#if WITH_EDITORONLY_DATA
{
if (DamageRadiusDebugSphere != nullptr)
{
DamageRadiusDebugSphere->DestroyComponent();
DamageRadiusDebugSphere = nullptr;
}
}
#endif
}
void URadialDamageComponent::Validate_OwnerCanBeDamaged() const
{
const auto Owner = GetOwner();
if (Owner && !Owner->CanBeDamaged())
{
UE_LOG(TanksVR, Warning, TEXT("%s"), *GetErrorMsg_OwnerCanBeDamaged());
}
}
FString URadialDamageComponent::GetErrorMsg_OwnerCanBeDamaged() const
{
const auto Owner = GetOwner();
const FString Message = FString::Printf(
TEXT("%s actor has disabled 'Can Be Damaged' option. Enabled it to activate RadialDamageComponent"),
*Owner->GetName());
return Message;
}
#if WITH_EDITORONLY_DATA
void URadialDamageComponent::AddReferencedObjects(UObject* InThis, FReferenceCollector& Collector)
{
auto This = CastChecked<URadialDamageComponent>(InThis);
Collector.AddReferencedObject(This->DamageRadiusDebugSphere);
Super::AddReferencedObjects(InThis, Collector);
}
void URadialDamageComponent::PostEditChangeProperty(FPropertyChangedEvent& PropertyChangedEvent)
{
Super::PostEditChangeProperty(PropertyChangedEvent);
RefreshVisualRepresentation();
Validate_OwnerCanBeDamaged();
}
void URadialDamageComponent::RefreshVisualRepresentation()
{
if (DamageRadiusDebugSphere != nullptr)
{
DamageRadiusDebugSphere->SetSphereRadius(DamageRadius);
}
}
#endif