C++ How to set Sprite when extending SceneComponent

How to set a Billboard Sprite on a class extending from SceneComponent?

Here is my constructor, this doesn’t work.

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<UTexture2D> NoteTextureObject;

		// 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
			: NoteTextureObject(TEXT("/Game/Blueprints/icons/AmmoMarker"))
			, ID_CatagoryName(TEXT("Marker"))
			, NAME_DisplayName(NSLOCTEXT("SpriteCategory", "AmmoMarker", "AmmoMarker"))
		{
		}
	};
	static FConstructorStatics ConstructorStatics;

#if WITH_EDITORONLY_DATA
	//SpriteComponent = ObjectInitializer.CreateEditorOnlyDefaultSubobject<UBillboardComponent>(this, TEXT("Sprite"));
	if (SpriteComponent)
	{

		SpriteComponent->Sprite = ConstructorStatics.NoteTextureObject.Get();		// Get the sprite texture from helper class object
		SpriteComponent->SpriteInfo.Category = ConstructorStatics.ID_CatagoryName;		// Assign sprite category name
		SpriteComponent->SpriteInfo.DisplayName = ConstructorStatics.NAME_DisplayName;	// Assign sprite display name
		SpriteComponent->AttachParent = this;				        // Attach sprite to scene component
		SpriteComponent->Mobility = EComponentMobility::Static;
	}
#endif // WITH_EDITORONLY_DATA

chirp chirp

I got this working and am posting for others convenience. I changed the constructor function to ObjectInitializer.CreateEditorOnlyDefaultSubobject

The last variable made the most difference. If bTransient is false as it is by default, this crashed with an error about mismatch of template and instance type.

I am not calling RegisterComponent(), that causes a crash and doesn’t seem needed when using the ObjecInitializer.

UTokenMarker::UTokenMarker(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
bWantsInitializeComponent = true;
PrimaryComponentTick.bCanEverTick = true;

// Structure for Sprite Info
struct FConstructorStatics
{
		ConstructorHelpers::FObjectFinderOptional<UTexture2D>MarkerTextureObject;

	// Icon sprite category name
	FName ID_CatagoryName;

	// Icon sprite display name
	FText NAME_DisplayName;

FConstructorStatics() : MarkerTextureObject(TEXT("/Game/MyGameName/Procedural/Blocks/Blueprints/icons/TokenMarker"))
, ID_CatagoryName(TEXT("Marker"))
, NAME_DisplayName(NSLOCTEXT("SpriteCategory", "TokenMarker", "TokenMarker"))
		{
		}
	};
static FConstructorStatics ConstructorStatics;

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

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

	BillboardComponent->AttachTo(this);
}
1 Like