Spline mesh components not visible in editor

Hi, I’m following this tutorial (link text) but I’m doing in in C++ instead of blueprint. The issue I have is that the Static Meshes of the Spline Mesh Components are not visible in the editor, unless I go in PIE mode.

My code is below. Note that if you to hit the REFRESH checkbox under the Details tab to update the component (also, make sure to select a static mesh!)

Thanks!

TrackData.h

#pragma once

#include "TrackData.generated.h"

USTRUCT(BlueprintType)
struct FTrackData
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, Category = "GuardRail")
		bool LeftGuardRail = true;

	UPROPERTY(EditAnywhere, Category = "GuardRail")
		bool RightGuardRail = true;

	UPROPERTY(EditAnywhere, Category = "Geometry")
		float Width = 15.f;

	UPROPERTY(EditAnywhere, Category = "Geometry")
		float Thickness = 1.f;

	UPROPERTY(EditAnywhere, Category = "Geometry")
		float Bank = 0.f;
};

TrackGenerator.h

#pragma once

#include "GameFramework/Actor.h"
#include "TrackData.h"
#include "TrackGenerator.generated.h"

class USplineComponent;
class USplineMeshComponent;
//struct FTrackData;

UCLASS()
class RETRO_API ATrackGenerator : public AActor
{
	GENERATED_BODY()
	
private:
	UPROPERTY(EditAnywhere, Category = "_REFRESH")
		bool REFRESH = false;
public:	
	// Sets default values for this actor's properties
	ATrackGenerator();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

	USceneComponent *SceneComponent = nullptr;

	UPROPERTY(EditAnywhere, Category = "Spline")
		USplineComponent *SplineComponent = nullptr;

	UPROPERTY(VisibleAnywhere, Category = "Spline")
		int8 NbSplinePoints;

	UPROPERTY(EditAnywhere, Category = "TrackData")
		TArray<FTrackData> TrackData;

private:
#if WITH_EDITOR
	virtual void PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent) override;
	void DestroySplineComponents();
#endif

	void BuildTrackElement(int Index, UStaticMesh *Mesh);

	UPROPERTY(EditAnywhere, Category = "Spline")
		UStaticMesh *StaticMesh = nullptr;

	UPROPERTY(VisibleAnywhere, Category = "Spline")
		TArray<USplineMeshComponent*> SplineMeshComponents;
};

TrackGenerator.cpp

#include "Retro.h"
#include "Runtime/Engine/Classes/Components/SplineComponent.h"
#include "Runtime/Engine/Classes/Components/SplineMeshComponent.h"
#include "TrackGenerator.h"


// Sets default values
ATrackGenerator::ATrackGenerator()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = false;

	SceneComponent = CreateDefaultSubobject<USceneComponent>(FName("SceneComponent"));
	SceneComponent->SetMobility(EComponentMobility::Static);
	SetRootComponent(SceneComponent);

	SplineComponent = CreateDefaultSubobject<USplineComponent>(FName("SplineComponent"));
	SplineComponent->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
	SplineComponent->SetMobility(EComponentMobility::Static);
}

#if WITH_EDITOR
void ATrackGenerator::PostEditChangeProperty(FPropertyChangedEvent & PropertyChangedEvent)
{
	Super::PostEditChangeProperty(PropertyChangedEvent);

	REFRESH = false;

	UE_LOG(LogTemp, Warning, TEXT("PostEditChangeProperty"));
	DestroySplineComponents();

	NbSplinePoints = SplineComponent->GetNumberOfSplinePoints();
	while (TrackData.Num() != NbSplinePoints)
	{
		if (TrackData.Num() < NbSplinePoints)
		{
			TrackData.Push(FTrackData());
		}

		else if (TrackData.Num() > NbSplinePoints)
		{
			TrackData.Pop();
		}
	}

	if (StaticMesh)
	{
		for (int8 i = 0; i < NbSplinePoints - 1; i++)
		{
			UE_LOG(LogTemp, Warning, TEXT("Building: %i"), i);
			BuildTrackElement(i, StaticMesh);
		}
	}
}


void ATrackGenerator::DestroySplineComponents()
{
	int8 NbPointsToDestroy = SplineMeshComponents.Num();
	for (int8 i = 0; i < NbPointsToDestroy; i++)
	{
		UE_LOG(LogTemp, Warning, TEXT("DELETING: %i"), i);
		USplineMeshComponent *Component = SplineMeshComponents.Pop();
		if (Component)
		{
			Component->DestroyComponent();
		}
	}
	UE_LOG(LogTemp, Warning, TEXT("SplineMeshComponents.Num(): %i"), SplineMeshComponents.Num());
}
#endif

void ATrackGenerator::BuildTrackElement(int Index, UStaticMesh *Mesh)
{
	// Store relevant data for each track element
	FVector LocalLocationStart;
	FVector LocalTangentStart;
	SplineComponent->GetLocalLocationAndTangentAtSplinePoint(Index, LocalLocationStart, LocalTangentStart);

	FVector LocalLocationEnd;
	FVector LocalTangentEnd;
	int NextIndex = (Index + 1) % NbSplinePoints;
	SplineComponent->GetLocalLocationAndTangentAtSplinePoint(NextIndex, LocalLocationEnd, LocalTangentEnd);

	// Use stored data to build track element
	USplineMeshComponent *SplineMeshComponent = NewObject<USplineMeshComponent>(SplineComponent);
	SplineMeshComponent->SetStaticMesh(Mesh);
	SplineMeshComponent->SetStartAndEnd(LocalLocationStart, LocalTangentStart, LocalLocationEnd, LocalTangentEnd);
	SplineMeshComponent->AttachToComponent(GetRootComponent(), FAttachmentTransformRules::KeepRelativeTransform);
	SplineMeshComponent->bVisible = true;
	SplineMeshComponent->SetMobility(EComponentMobility::Static);
	SplineMeshComponent->bSmoothInterpRollScale = true;
	SplineMeshComponent->SetCollisionProfileName(FName("BlockAll"));
	SplineMeshComponent->SetStartRoll(TrackData[Index].Bank);
	SplineMeshComponent->SetStartScale(FVector2D(TrackData[Index].Width, TrackData[Index].Thickness));
	SplineMeshComponent->SetEndRoll(TrackData[NextIndex].Bank);
	SplineMeshComponent->SetEndScale(FVector2D(TrackData[NextIndex].Width, TrackData[NextIndex].Thickness));
	SplineMeshComponents.Push(SplineMeshComponent);

	UE_LOG(LogTemp, Warning, TEXT("Index:%i   LocationStart:%s    TangentStart:%s   LocationEnd:%s    TangentEnd:%s"), Index, *LocalLocationStart.ToString(), *LocalTangentStart.ToString(), *LocalLocationEnd.ToString(), *LocalTangentEnd.ToString());
}

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

// Called every frame
void ATrackGenerator::Tick( float DeltaTime )
{
	Super::Tick( DeltaTime );
}
1 Like

Also, if I save my project, close UE and reopen it, the static meshes are visible but as soon as I edit the Spline Component, they all disappear… I have no idea what’s going on… Any help would be much appreciated.

2 Likes