How to derive a class from ALight class?

Hi, I want to create an AFlickeringLight class from the ALight class. I tried to do it, but because the light component is private, I can not access it, if I add another light component in my class, then it defeats the whole purpose of inheritance, especially when I need to use this class with my light switch class to on/off the light by accessing its light component.
This class works with the already defined light types, but I can’t use it with my class because I use a new light component instead of the one from the base class.

This is the code for my flickering light class:

FlickeringLight.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Engine/Light.h"
#include "FlickeringLight.generated.h"

class UPointLightComponent;

UCLASS()
class UDEMYHORRORGAME_API AFlickeringLight : public ALight
{
    GENERATED_BODY()

public:
    // Sets default values for this actor's properties
    AFlickeringLight();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

    UPROPERTY(VisibleAnywhere, BlueprintReadOnly)
    TObjectPtr<UPointLightComponent>PointLight;

    UPROPERTY(EditAnywhere, Category = "Flicker")
    float MaxFlickerIntersity{ 5000.0f };

    UPROPERTY(EditAnywhere, Category = "Flicker")
    float MinFlickerIntersity{ 2000.0f };

    UPROPERTY(EditAnywhere, Category = "Flicker")
    float MinDelayTime{ 0.8 };

    UPROPERTY(EditAnywhere, Category = "Flicker")
    float MaxDelayTime{ 0.2 };

    FLatentActionInfo FlickerActionInfo;

    UFUNCTION()
    void FlickerDelayCallback();

    void TriggerDelay();

};

FlickeringLight.cpp

// Fill out your copyright notice in the Description page of Project Settings.


#include "Actors/Light/FlickeringLight.h"
#include "Components/PointLightComponent.h"
#include "Kismet/KismetSystemLibrary.h"
#include "Kismet/KismetMathLibrary.h"

AFlickeringLight::AFlickeringLight() :
    PointLight(CreateDefaultSubobject<UPointLightComponent>(TEXT("PointLight")))
{
    RootComponent = PointLight;

    PointLight->SetIntensity(MaxFlickerIntersity);
    FlickerActionInfo = FLatentActionInfo(0, 0, *FString(TEXT("FlickerDelayCallback")), this);
}

void AFlickeringLight::BeginPlay()
{
    Super::BeginPlay();

    TriggerDelay();
}

void AFlickeringLight::FlickerDelayCallback()
{
    float Intensity = UKismetMathLibrary::RandomFloatInRange(MinFlickerIntersity, MaxFlickerIntersity);
    PointLight->SetIntensity(Intensity);
    TriggerDelay();
}

void AFlickeringLight::TriggerDelay()
{
    float Delay = UKismetMathLibrary::RandomFloatInRange(MinDelayTime, MaxDelayTime);
    UKismetSystemLibrary::RetriggerableDelay(this, Delay, FlickerActionInfo);
}

Any help will be appreciated, thanks in advance.

It seems that the LightComponent is private just to prevent its pointer value from being changed.

This component should still be fully accessible via ALight::GetLightComponent method:

…which as I understand is exactly what you’ve been looking for, right? Have you tried this already?

Sorry, if I’m missing something here :smiley:

I tried that already but it was returning nullptr, that’s my main problem because the component from the base class is not initialising.

TLDR

If you don’t care about how I found it, just read the SOLUTION down below.


EXPLANATION

You’re right. I can see the same behavior on my side:

For some reason when default constructor ALight::ALight gets called, the CreateDefaultSubobject always fails, returning nullptr:

Not sure why is this happening (maybe, because ALight class is marked as Abstract? idk).
I had hard time stepping into the CreateDefaultSubobject function and debugging it.
I’m also not really sure how it is supposed to work.

However,

every Light class seems to be also implementing additional sub-class of ULightComponent and calling ALight::ALight manually, in the following way:

So, I had to create a new dummy Class derived from ULightComponent
and I implemented the same constructor for my Light Actor class.

The problem is fixed on my side (LightComponent isn’t nullptr any more):


SOLUTION

  1. Create new dummy component class derived from ULightComponent (you wanted to use UPointLightComponent in your code, so u can use it instead).
  2. In .h of your Light Actor class, declare constructor that takes const FObjectInitializer& ObjectInitializer as parameter…
  3. … and when defining said constructor in .cpp, call Super(ObjectInitializer.SetDefaultSubobjectClass<UMyLightComponent>(TEXT("LightComponent0"))), where SetDefaultSubobjectClass function should take your dummy component class as template parameter.
  4. Make sure to include all headers and modules

MyLight.h

#pragma once

#include "CoreMinimal.h"
#include "Engine/Light.h"
#include "Components/LightComponent.h"
#include "MyLight.generated.h"

/* step 1 - dummy component class */
UCLASS(Blueprintable)
class MYPROJECT_API UMyLightComponent : public ULightComponent
{
	GENERATED_BODY()
};

UCLASS(Blueprintable)
class MYPROJECT_API AMyLight : public ALight
{
	GENERATED_BODY()
	
	/* step 2 - constructor that takes FObjectInitializer */
	AMyLight(const FObjectInitializer& ObjectInitializer);
};

MyLight.cpp

#include "MyLight.h"
#include "Components/LightComponent.h"

/* step 3 - call to Super constructor */
AMyLight::AMyLight(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer.SetDefaultSubobjectClass<UMyLightComponent>(TEXT("LightComponent0")))
{}

I was really interested in this one and spend some time figuring it out.
I hope this will help you :slight_smile:

Let me know if this works.
if not, I’ll be really really annoyed…

Hi dzemzmcdonalda, sorry for the late reply, I was occupied because of some IRL issues.
The solution worked, thank you very much.
You are awesome.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.