Hi! I am making a class derived from Character. This class creates an instance of a “Cover Helper” Class (derived from Scene Component) using createDefaultSubobject(). The problem is that this Cover Helper instance becomes invalid for some reason which hinders me from using it’s function findCoverNear(). I checked if it is valid using IsValid() on several different occasions, in the constructor, in BeginPlay() and in Tick(). I also check via Blueprints through a Blueprint class derived from my custom character class. Only the check inside the constructor comes back as valid. I don’t understand how this can happen! It have been looking around the internet but can’t seem to find any solution, help would be much appreciated! source and header files pasted below
my custom character class (.cpp):
#include "AdvancedCharacter.h"
// Sets default values
AAdvancedCharacter::AAdvancedCharacter(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer.SetDefaultSubobjectClass<UAdvCharMovementComponent>(ACharacter::CharacterMovementComponentName))
{
if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Yellow, TEXT("test")); }
//MovementComponent = Cast<UAdvCharMovementComponent>(GetMovementComponent());
CoverHelper = CreateDefaultSubobject<UCoverHelper>(TEXT("CoverHelperObject"));
CoverHelper->SetupAttachment(RootComponent);
if (IsValid(CoverHelper))
{
if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, TEXT("isValid")); }
}
else {
if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Blue, TEXT("notValid")); }
}
// Set this character to call Tick() every frame. You can turn this off to improve performance if you don't need it.
PrimaryActorTick.bCanEverTick = true;
}
// Called when the game starts or when spawned
void AAdvancedCharacter::BeginPlay()
{
Super::BeginPlay();
if (IsValid(CoverHelper))
{
if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, TEXT("isValid")); }
}
else {
if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Green, TEXT("notValid")); }
}
}
// Called every frame
void AAdvancedCharacter::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
if (IsValid(CoverHelper))
{
if (GEngine) { GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Red, TEXT("isValid")); }
}
else {
if (GEngine) { GEngine->AddOnScreenDebugMessage(1, 2.0f, FColor::Red, TEXT("notValid")); }
}
}
// Called to bind functionality to input
void AAdvancedCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
Super::SetupPlayerInputComponent(PlayerInputComponent);
}
UCoverHelper *AAdvancedCharacter::GetCoverHelper()
{
return CoverHelper;
}
custom character class (.h)
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "AdvCharMovementComponent.h"
#include "CoverHelper.h"
#include "AdvancedCharacter.generated.h"
UCLASS()
class ADVCHARPROJ_API AAdvancedCharacter : public ACharacter
{
GENERATED_UCLASS_BODY()
public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly ,BlueprintGetter = "GetCoverHelper")
class UCoverHelper *CoverHelper;
UFUNCTION(BlueprintGetter)
UCoverHelper *GetCoverHelper();
protected:
// Called when the game starts or when spawned
virtual void BeginPlay() override;
public:
// Called every frame
virtual void Tick(float DeltaTime) override;
// Called to bind functionality to input
virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
UAdvCharMovementComponent *MovementComponent;
};
CoverHelper.cpp:
#include "CoverHelper.h"
// Sets default values for this component's properties
UCoverHelper::UCoverHelper()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;
//isActive = false;
CharacterOwner = this->GetAttachmentRootActor();
//UAdvCharMovementComponent *MovementComponent = Cast<UAdvCharMovementComponent>(CharacterOwner->GetMovementComponent());
// ...
}
// Called when the game starts
void UCoverHelper::BeginPlay()
{
Super::BeginPlay();
// ...
}
// Called every frame
void UCoverHelper::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
// ...
}
bool UCoverHelper::FindCoverNearest(float range)
{
bool validCover = false;
FVector startLocation = CharacterOwner->GetActorLocation();
FHitResult prevHit;
FCollisionQueryParams CollisionParams;
CollisionParams.AddIgnoredActor(CharacterOwner);
for (int i = 0; i < 8; i++) {
if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Yellow, TEXT("for")); }
FRotator rot = FRotator(0, i * 45,0);
FHitResult Hit;
FVector direction = FVector(range, 0, 0);
FVector endLocation = startLocation + rot.RotateVector(direction);
validCover = GetWorld()->LineTraceSingleByChannel(Hit, startLocation, endLocation, ECollisionChannel::ECC_WorldDynamic, CollisionParams);
DrawDebugLine(GetWorld(), startLocation, endLocation, FColor::Green, true, -1, 0, 2.f);
if (validCover) {
if (GEngine) { GEngine->AddOnScreenDebugMessage(-1, 2.0f, FColor::Yellow, TEXT("validCover")); }
float dist = Hit.Distance;
if (prevHit.bBlockingHit) {
prevHit = Hit;
}
else if (Hit.Distance < prevHit.Distance) {
prevHit = Hit;
}
}
}
return validCover;
}
bool UCoverHelper::FindCoverDirectional(FQuat direction, float range)
{
bool validCover = false;
//raycast logic
return validCover;
}
void UCoverHelper::SetIsActive(bool b)
{
//isActive = b;
}
bool UCoverHelper::GetIsActive()
{
return false;
}
CoverHelper.h:
#pragma once
#include "CoreMinimal.h"
#include "EngineGlobals.h"
#include "Components/SceneComponent.h"
#include "AdvancedCharacter.h"
#include "DrawDebugHelpers.h"
#include "CoverHelper.generated.h"
UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class ADVCHARPROJ_API UCoverHelper : public USceneComponent
{
GENERATED_BODY()
public:
// Sets default values for this component's properties
UCoverHelper();
AActor *CharacterOwner;
protected:
// Called when the game starts
virtual void BeginPlay() override;
public:
// Called every frame
virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
UFUNCTION(BlueprintCallable)
bool FindCoverNearest(float range);
bool FindCoverDirectional(FQuat direction, float range);
void SetIsActive(bool b);
bool GetIsActive();
};