UE4 C++ How to make Component with Billboard SubComponent

UE4 Blueprints makes it very easy to drag and drop objects onto each other, but sometimes you want everything already set up.

I’ve been working on a procedural level generation system, which is designer assisted. So blocks that will be assembled to build a level need to be marked up by the designer with locations to spawn items and other things.

Doing this in Blueprints is very easy, make a new Blueprint extending Actor, then press AddComponent, pick BillBoardComponent, set it’s Sprite in it’s details panel and you are done. But, it’s a Blueprint itself which means code that runs it will have to go looking for blueprint instances. Additionally, it gets messier when the Blueprint extends Blueprint Component, and then these need to be added to each block.

So, moving all this to C++.

The result will be that when the designer is modifying a Block they will press add component, and select the one they want directly, then position it.

BlockWithComponents

 

It actually is very simple, but because it wasn’t directly documented it took me a while to figure it out. Here’s the code.

This is the base header file:

#pragma once

#include "Components/ActorComponent.h"
#include "Components/SceneComponent.h"
#include "Components/BillboardComponent.h"
#include "MarkerComp.generated.h"
UCLASS(Blueprintable, ClassGroup = (Marker), meta = (BlueprintSpawnableComponent))
class MYGAME_API UMarkerComp : public USceneComponent
{
GENERATED_BODY()

protected:
//A UBillboardComponent to hold Icon sprite
class UBillboardComponent* BillboardComponent;
//Sprite for the Billboard Component
class UTexture2D* SpriteTexture;

public:
// Sets default values for this component's properties
UMarkerComp(const FObjectInitializer& ObjectInitializer);

// Begin ActorComponent interface
virtual void OnRegister() override;

// Called when the game starts
virtual void InitializeComponent() override;

// Called every frame
virtual void TickComponent( float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction ) override;
};

I didn’t actually choose to make the Billboards in it’s .cpp, but in it’s derived classes. I use multiple because each type of marker in my system has different variables that need to be set as well as functions that will be called as the level is being generated, so it is more than just a different sprite.

#include "MyGame.h"
#include "MarkerComp.h"


// Sets default values for this component's properties
UMarkerComp::UMarkerComp(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	// 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.
	bWantsInitializeComponent = true;
	PrimaryComponentTick.bCanEverTick = true;

	//IconPath = "/Game/Lemons/Procedural/Blocks/Blueprints/icons/AmmoMarker";
	bVisualizeComponent = true;
}


void UMarkerComp::OnRegister()
{
	// If we need to perform a call to AttachTo, do that now
	// At this point scene component still has no any state (rendering, physics),
	// so this call will just add this component to an AttachChildren array of a the Parent component
	AttachTo(AttachParent, AttachSocketName);
	Super::OnRegister();
}

Here is the extending header.

#pragma once

#include "Components/ActorComponent.h"
#include "MarkerComp.h"
#include "AmmoMarker.generated.h"

UCLASS(ClassGroup = (Lemon), meta = (BlueprintSpawnableComponent))
class MYGAME_API UAmmoMarker : public UMarkerComp
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	UAmmoMarker(const FObjectInitializer& ObjectInitializer);

	// Called when the game starts
	virtual void InitializeComponent() override;

	// Called every frame
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;
	
	
};

Here is the .cpp of an extending class that actually makes the Billboard Component.

#include "MyGame.h"
#include "AmmoMarker.h"


// Sets default values
UAmmoMarker::UAmmoMarker(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.
	bWantsInitializeComponent = true;
	PrimaryComponentTick.bCanEverTick = true;

	// Structure to hold one-time initialization
	struct FConstructorStatics
	{
		// A helper class object we use to find target UTexture2D object in resource package
		ConstructorHelpers::FObjectFinderOptional MarkerTextureObject;

		// Icon sprite category name
		FName ID_CatagoryName;

		// Icon sprite display name
		FText NAME_DisplayName;

		FConstructorStatics()
			// Use helper class object to find the texture
			// "/Engine/EditorResources/S_Note" is resource path
			: MarkerTextureObject(TEXT("/Game/Lemons/Procedural/Blocks/Blueprints/icons/AmmoMarker"))
			, ID_CatagoryName(TEXT("Marker"))
			, NAME_DisplayName(NSLOCTEXT("SpriteCategory", "AmmoMarker", "AmmoMarker"))
		{
		}
	};
	static FConstructorStatics ConstructorStatics;

	BillboardComponent = ObjectInitializer.CreateEditorOnlyDefaultSubobject(this, TEXT("Billboard"), true);

	SpriteTexture = ConstructorStatics.MarkerTextureObject.Get();
	BillboardComponent->Sprite = SpriteTexture;

	BillboardComponent->AttachTo(this);
}
Share Button

Comments

UE4 C++ How to make Component with Billboard SubComponent — 2 Comments

    • Glad it helped. I refer back to some of these sometimes myself. I check in but am not actively writing these tutorials.

Leave a Reply

Your email address will not be published. Required fields are marked *