Questions about creating and using a custom Actor class

I’m trying to convert my Blueprint spline-based road to C++. My Blueprint is based on the “Unreal Engine 4 Training Twitch: Splines and Spline Components” video and works fine. However, I’m unsure about a few things when converting this to C++. I’ve written C++ before to make custom Blueprint nodes but I’ve never made a custom Actor before.

I created a class derived from AActor named ARoad. It is currently bare-bones and doesn’t do very much at the moment. Here is the cpp and header.

CPP



#include "MyPlugin.h"
#include "Road.h"

DEFINE_LOG_CATEGORY(MyLog);

ARoad::ARoad()
{
    // 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;

    // Create the spline component and set it as the root     
    m_splineComponent = NewObject<USplineComponent>(this, FName(TEXT("Spline")));
    m_splineComponent->SetMobility(EComponentMobility::Static);
    SetRootComponent(m_splineComponent);
}

void ARoad::OnConstruction( const FTransform& Transform ){
    Super::OnConstruction(Transform);
    
    UE_LOG(MyLog, Warning, TEXT("OnConstruction - numSplinePoints: %d"), m_splineComponent->GetNumSplinePoints());
    
    RegisterAllComponents();
}


HEADER



#pragma once

#include "GameFramework/Actor.h"
#include "Runtime/Engine/Classes/Components/SplineComponent.h"
#include "Road.generated.h"

// General log
DECLARE_LOG_CATEGORY_EXTERN(MyLog, Log, All)

UCLASS()
class MYPLUGIN_API ARoad : public AActor
{
    GENERATED_BODY()
	
public:	
    // Sets default values for this actor's properties
    ARoad();

    virtual void OnConstruction(const FTransform& Transform) override;

	
    UPROPERTY()
    USplineComponent* m_splineComponent;
};


  1. In the constructor, is calling SetRootComponent necessary to make m_splineComponent the root? Because it seems like the spline component is made root automatically without that call when I looked at it from the UE editor.

  2. After compilation, I see my Road class in the UE editor under C++ Classes -> MyPlugin. I’m unsure of how to use this. If I drag ‘Road’ to the scene and then try to save the scene, I get the error:

Can’t save City.umap: Graph is linked to private object(s) in an external package.
External Object(s):
Spline

I’ve tried creating a Blueprint class based on my Road class but this doesn’t seem to work correctly. I can drag the Blueprint onto my scene and my logging statements are called but when I try to save the Blueprint asset, I get the same error as above. What I’m supposed to do?

  1. I don’t know how how to connect an interface to this so I can set options in the UE editor. For example, in the UE editor, I will want to specify the static mesh that will be used in my spline mesh components. I’ve read the Hello Slate tutorial but I don’t understand how ARoad and the HUD are supposed to communicate. Is there a tutorial for this?

Am I supposed to use Blutility since I want in-editor access as opposed to in-game access? I tried phoboz’s tutorial but nothing showed up in the Blutility’s details panel (neither the function as a clickable button nor the text variable). Other posts seem to indicate that Blutility broken.

Any help would be appreciated. Thanks.

I was able to answer my own questions.

  1. I found out that if I don’t set the root component explicitly, AActor will set one of the scene components as root automatically in AActor::FixupNativeActorComponents(). That explains the behavior I was getting.

  2. I was able to fix this error by creating the spline component using CreateDefaultSubobject instead of NewObject. I don’t know understand what’s going on because I didn’t find documentation about this but it worked so…



ARoad::ARoad( const FObjectInitializer& 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;

    // Create the spline component and set it as the root component.
    SplineComponent = ObjectInitializer.CreateDefaultSubobject<USplineComponent>(this, FName(TEXT("Spline")));
    SplineComponent->SetMobility(EComponentMobility::Static);
    SetRootComponent(SplineComponent);
}


  1. I found out I need to set the variable’s UPROPERTY with BlueprintReadWrite. Here’s an example:


UPROPERTY(EditAnywhere, BlueprintReadWrite, Category=RoadSetup)
UStaticMesh* DefaultStaticMesh;