What is the C++ way of calling 'Add Spline Mesh Component'?

I am trying to recreate the blueprint spline track example in C++. In the Blueprint there is a ‘Add Spline Mesh Component’ call and I am not sure how I would translate this to C++.

I tried


void Foo::OnConstruction(const FTransform& Transform)
{
  int32 SplinePoints = Spline->GetNumSplinePoints();
  for (int32 i = 0; i < SplinePoints; ++i){
    FVector Location, Tangent;
    Spline->GetLocalLocationAndTangentAtSplinePoint(i, Location, Tangent);
    USplineMeshComponent *s = CreateDefaultSubobject<USplineMeshComponent>(TEXT(""));
    ...
  }
}

but this crashes the editor. I just want to spawn a SplineMeshComponent in the construction script, how would I do that?

I also tried


void ASurfMeshGenerator::OnConstruction(const FTransform& Transform)
{
  int32 SplinePoints = Spline->GetNumSplinePoints() - 1;
  for (int32 i = 0; i < SplinePoints; ++i){
    FVector Location, Tangent, LocationNext, TangentNext;
    Spline->GetLocalLocationAndTangentAtSplinePoint(i, Location, Tangent);
    Spline->GetLocalLocationAndTangentAtSplinePoint(i + 1, LocationNext, TangentNext);
    auto *s = ConstructObject<USplineMeshComponent>(USplineMeshComponent::StaticClass(), GetOwner());
    s->SetStaticMesh(Mesh);
    s->SetStartAndEnd(Location, Tangent, LocationNext,TangentNext);
  }
}

but s-&gt;SetStartAndEnd(Location, Tangent, LocationNext,TangentNext); results also in an editor crash. Is ConstructObject also wrong?

Okay it seems that I have missued the API.


void AFoo::OnConstruction(const FTransform& Transform)
{
    USplineMeshComponent *s = ConstructObject<USplineMeshComponent>(USplineMeshComponent::StaticClass());
    FVector v(10,10,10);
    s->SetStaticMesh(Mesh);
    s->SetStartAndEnd(v, v, v,v);
}

The following code throws the error


bool UWorld::AreActorsInitialized() const
{
	return PersistentLevel && PersistentLevel->Actors.Num() && bActorsInitialized;
}

Where PersistentLevel “is unable to read memory”. Is it incorrect to use ConstructObject in OnConstruction?


s->SetStartAndEnd(v, v, v,v);

Is the line that is “responsible” because it calls


void USplineMeshComponent::MarkSplineParamsDirty()
{
	MarkRenderStateDirty();

#if WITH_EDITOR
	if (!GetWorld()->AreActorsInitialized())
	{
		RecreateCollision();
	}
#endif // WITH_EDITOR
}

Any help is greatly appreciated.

I followed the guide here:

I think the line causing your issue is


USplineMeshComponent *s = ConstructObject<USplineMeshComponent>(USplineMeshComponent::StaticClass());

When it should be


USplineMeshComponent *s = ConstructObject<USplineMeshComponent>(USplineMeshComponent::StaticClass(), this);

Using the guide I was able to get the meshes to appear, but the problem I am having is that the guide uses


bCreatedByConstructionScript

which is now deprecated. Even if I try to use this value, it seems that my meshes are not deleted when construction is rerun, so I am spawning hundreds of meshes each time I move my spline around. Can anyone show me how to properly destroy meshes which were created during construction?

I would be greatly interested in this as well!

Instead of bCreatedByConstructionScript, you should now set the CreationMethod property to EComponentCreationMethod::UserConstructionScript.

Epic should update their documentation faster.

This has been changed now to NewObject<UObjectType>(InParent, Class, Name, Flags). ConstructObject was deprecated.

5 Likes

After searching through various posts, even though this is an old thread, this was the most relevant topic, so I thought I’d expand on this with an example that I’m using in my game:

USplineMeshComponent* smc = NewObject<USplineMeshComponent>(this, USplineMeshComponent::StaticClass());
if (smc)
{	
	smc->AttachToComponent(splineComponent, FAttachmentTransformRules::KeepRelativeTransform);
	smc->RegisterComponent();
	AddInstanceComponent(smc);	
}
3 Likes