[C++] Why AHUD class cannot be placed into the world?

The GIF shows me dragging the CubeTrigger C++ class into the world.

35293-ue4_error1.gif

However, the Editor doesn’t allow me to do so.

Does anyone know why?


Code given below:

CubeTrigger.h

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

#pragma once

#include "GameFramework/Actor.h"
#include "CubeTrigger.generated.h"

//Exposing the struct that variables can be editable in blueprints
USTRUCT(BlueprintType) 
struct FCustomText {
	GENERATED_USTRUCT_BODY()

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=CustomProperties) FString Text;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = CustomProperties) FVector2D Position;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = CustomProperties) FVector2D Scale;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = CustomProperties) FColor Color;
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = CustomProperties) UFont* Font;
};


UCLASS()
class MYFPSPROJECT_API ACubeTrigger : public AHUD
{
	GENERATED_BODY()
	
public:	
	//Properties
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=CustomProperties) FString TriggerMessage;

	//Text struct
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=CustomProperties) struct FCustomText TextStruct;

	//BoxTrigger component
	UPROPERTY(VisibleAnywhere, Category=CustomProperties) UBoxComponent* CubeTriggerComponent;

	//Class only variables
	bool HasTriggered;
	APlayerController* PlayerController;



	// Sets default values for this actor's properties
	ACubeTrigger(const FObjectInitializer& ObjectInitializer);

	//Override functions
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	virtual void Tick( float DeltaSeconds ) override;
	virtual void DrawHUD() override;
	virtual void PostInitializeComponents() override;
	
	//Function
	//Overlapping functions
	UFUNCTION() void OnBeginOverlap(AActor* OtherActor);
	UFUNCTION() void OnEndOverlap(AActor* OtherActor);
	
};

CubeTrigger.cpp

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

#include "MyFPSProject.h"
#include "CubeTrigger.h"


// Sets default values
ACubeTrigger::ACubeTrigger(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	//Initializing BoxTrigger component
	this->CubeTriggerComponent = ObjectInitializer.CreateDefaultSubobject<UBoxComponent>(this, TEXT("CubeTriggerComponent"));
	this->SetRootComponent(this->CubeTriggerComponent);

	//Setting up blueprint overlapping events.
	this->OnActorBeginOverlap.AddDynamic(this, &ACubeTrigger::OnBeginOverlap);
	this->OnActorEndOverlap.AddDynamic(this, &ACubeTrigger::OnEndOverlap);

	//Initializing trigger messages.
	this->TriggerMessage = FString("");

	//Initializing Text struct
	ConstructorHelpers::FObjectFinder<UFont> FontObject(TEXT("Font'/Engine/EngineFonts/Roboto.Roboto'"));
	if (FontObject.Succeeded()){
		this->TextStruct.Font = FontObject.Object;
	}
	this->TextStruct.Color = FColor::FromHex("CCCCCC");
	this->TextStruct.Position = FVector2D(0.0f, 0.0f);
	this->TextStruct.Scale = FVector2D(0.4f, 0.7f);
}

// Called when the game starts or when spawned
void ACubeTrigger::BeginPlay()
{
	Super::BeginPlay();
}

// Called every frame
void ACubeTrigger::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );

}

void ACubeTrigger::OnBeginOverlap(AActor* OtherActor){
	if (!this->HasTriggered){
		if (GEngine){
			LOG(this->TriggerMessage);
		}
	}
}

void ACubeTrigger::OnEndOverlap(AActor* OtherActor){
	this->HasTriggered = true;
}

void ACubeTrigger::DrawHUD(){
	Super::DrawHUD();

	this->DrawText(this->TriggerMessage, this->TextStruct.Position, this->TextStruct.Font, this->TextStruct.Scale, this->TextStruct.Color);
}

void ACubeTrigger::PostInitializeComponents(){
	Super::PostInitializeComponents();

	this->PlayerController = this->GetOwningPlayerController();
}

The reason AHUD can’t be placed in the world is because of one of the following possibilities:

  1. The actor has not been ObjectIntialized in the constructor.
  2. There is no root component attached as parent of the class.

There may be more possibilities, but these are the only few I know of that does this.

AHUD is never manually instantiated on the scene.

Use ClientSetHUD on the active PlayerController object, like this:

APlayerController *player = ...;
player->ClientSetHUD(ACubeTrigger::StaticClass());

Or like this in blue print:

It’s way easier as you think.

Normaly actors can be placed in the world, so it’s okay to question why the HUD can’t be placed.

The answer is: He isn’t allowed to be placed.

How do i know that? I looked up the header file in the Source Code.

You know the Properties you can set for a UPROPERTY right? There are also some for the UCLASS in the header file. The important one hier is:

notplaceable

Here is the UCLASS of the HUD.h

UCLASS(config=Game, hidecategories=(Rendering,Actor,Input,Replication), showcategories=("Input|MouseInput", "Input|TouchInput"), notplaceable, transient, BlueprintType, Blueprintable)

So he is just not meant to be placed. You would need to change that, but there is no reason to place it.

This supports a feature request I made to have visual cues in UE4 so that we won’t get confused like this.