Hi Forum. First time posting here. Looking for input/suggestions as I don’t even know if I have the correct approach.
I am working on a spline that constantly grows forward. Any type of splines I’ve used works fine. i can add new meshes as it grows and even inside OnConstruction
, but I am trying to keep it performant. Imagine an endless runner but using a spline instead of spawning/de-spawning components, but a spline to easily add tangents/curves.
I am trying an approach where I have a mesh pool and reposition them as the spline grows forward, but I haven’t been able to even render the meshes them on game mode. What I had in mind was that this spline will have something like 20 meshes instantiated in memory and as it grows, reposition them so these 20 are always on screen.
Is this even the correct approach?? any suggestions?
Here’s my current code:
// Spline Tool.
#include "SplineTool.h"
#include "FindInBlueprints.h"
#include "SWarningOrErrorBox.h"
#include "Components/PrimitiveComponent.h"
#include "Components/InstancedStaticMeshComponent.h"
#include "Components/SplineComponent.h"
#include "Components/SplineMeshComponent.h"
ASplineTool::ASplineTool()
{
PrimaryActorTick.bCanEverTick = true;
SplineComponent = CreateDefaultSubobject<USplineComponent>(TEXT("SplineComponent"));
RootComponent = SplineComponent;
InstancedStaticMeshComponent = CreateDefaultSubobject<UInstancedStaticMeshComponent>(TEXT("InstancedStaticMeshComponent"));
if (InstancedStaticMeshComponent)
{
// UE_LOG(LogTemp, Display, TEXT("Creating InstancedStaticMeshComponent..."));
InstancedStaticMeshComponent->SetupAttachment(GetRootComponent());
}
else
{
UE_LOG(LogTemp, Error, TEXT("InstancedStaticMeshComponent not created..."));
}
}
void ASplineTool::OnConstruction(const FTransform& Transform)
{
Super::OnConstruction(Transform);
BaseSpline();
}
USplineMeshComponent* ASplineTool::CreateSplineMesh()
{
FName SplineMeshName = *FString::Printf(TEXT("SplineMesh_%d"), MeshPool.Num());
USplineMeshComponent* SplineMesh = NewObject<USplineMeshComponent>(this, USplineMeshComponent::StaticClass());
SplineMesh->SetForwardAxis(MeshForwardAxis);
SplineMesh->SetStaticMesh(Mesh);
// Setting collision.
if (bEnableCollision)
{
// UE_LOG(LogTemp, Warning, TEXT("Spline Collision Enabled"));
SplineMesh->SetCollisionProfileName(TEXT("BlockAll"));
SplineMesh->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
SplineMesh->SetCollisionObjectType(ECollisionChannel::ECC_WorldDynamic);
}
SplineMesh->RegisterComponentWithWorld(GetWorld());
SplineMesh->CreationMethod = EComponentCreationMethod::UserConstructionScript;
SplineMesh->SetMobility(EComponentMobility::Movable);
SplineMesh->AttachToComponent(SplineComponent, FAttachmentTransformRules::KeepRelativeTransform);
// Visibility.
SplineMesh->RegisterComponent();
SplineMesh->SetVisibility(true);
SplineMesh->SetHiddenInGame(false);
SplineMesh->SetWorldLocation(GetActorLocation());
UE_LOG(LogTemp, Warning, TEXT("Spline Tool created mesh %s"), *SplineMesh->GetName());
return SplineMesh;
}
void ASplineTool::BaseSpline()
{
if (!Mesh)
{
UE_LOG(LogTemp, Error, TEXT("Spline Tool: Mesh is null"));
return;
}
// Initializing mesh pool.
if (MeshPool.Num() == 0)
{
for (int i = 0; i < MaxSegments; i++)
{
USplineMeshComponent* SplineMesh = CreateSplineMesh();
MeshPool.Add(SplineMesh);
}
}
UE_LOG(LogTemp, Warning, TEXT("Spline Mesh set."));
int InstancesNumber = SplineComponent->GetNumberOfSplinePoints();
// UE_LOG(LogTemp, Warning, TEXT("There are %d spline points."), InstancesNumber);
// Get mesh bounding boxes to properly create the spline and its edges.
FBox BoundingBox = Mesh->GetBoundingBox();
FVector MinAbs = BoundingBox.Min.GetAbs();
FVector MaxAbs = BoundingBox.Max.GetAbs();
float XLength = MinAbs.X + MaxAbs.X;
// Get the spline length and divide it by the bounding box so it becomes the upper bound.
float SplineLength = SplineComponent->GetSplineLength();
int SplineTotal = FMath::CeilToInt(SplineLength / (XLength + InstancesNumber));
UE_LOG(LogTemp, Warning, TEXT("There were %d meshes in the pool"), MeshPool.Num());
for (int CurrentSpline = 0; CurrentSpline < SplineTotal; CurrentSpline++)
{
// Growth.
// UE_LOG(LogTemp, Warning, TEXT("The spine will be from %d to %d"), AllowedMinSegment, CurrentSpline);
// Rendering just the meshes. Thing is that this doesn't work on game mode as the spline is not rebuilt.
// What seems to be the solution is to physically keep a pool of meshes and change their location as the
// actor moves forward.
int MeshIndex = CurrentSpline;
if (MeshIndex >= MeshPool.Num())
{
MeshIndex = CurrentSpline % MaxSegments;
}
UE_LOG(LogTemp, Warning, TEXT("Rendering spline index: %d with %d meshes allowed"), MeshIndex, MaxSegments);
// UpdateSplineMeshLocations(CurrentSpline, CreateSplineMesh(), XLength);
UpdateSplineMeshLocations(CurrentSpline, MeshPool[MeshIndex], XLength);
// Logging
// After pool creation
for (auto* Mesh : MeshPool)
{
UE_LOG(LogTemp, Warning, TEXT("Mesh visibility: %d, IsRegistered: %d"),
Mesh->IsVisible(),
Mesh->IsRegistered());
}
}
UE_LOG(LogTemp, Warning, TEXT("-----------"));
}
void ASplineTool::UpdateSplineMeshLocations(int CurrentSpline, USplineMeshComponent* SplineMesh, float MeshXLength)
{
// Define the positions of the points and tangents.
// Multiply the index by the XLength.
float SegmentStart = CurrentSpline * MeshXLength;
float SegmentEnd = SegmentStart + MeshXLength;
// Starting spline render.
const FVector StartPoint = SplineComponent->GetLocationAtDistanceAlongSpline(SegmentStart, ESplineCoordinateSpace::Local);
const FVector StartTangent = SplineComponent->GetTangentAtDistanceAlongSpline(SegmentStart, ESplineCoordinateSpace::Local);
// Clamping vector size for tangents.
const FVector ClampedStartTangent = StartTangent.GetClampedToMaxSize(MeshXLength);
// Ending spline render.
const FVector EndPoint = SplineComponent->GetLocationAtDistanceAlongSpline(SegmentEnd, ESplineCoordinateSpace::Local);
const FVector EndTangent = SplineComponent->GetTangentAtDistanceAlongSpline(SegmentEnd, ESplineCoordinateSpace::Local);
// Clamping vector size for tangents.
const FVector ClampedEndTangent = EndTangent.GetClampedToMaxSize(MeshXLength);
// Rendering...
SplineMesh->SetStartAndEnd(StartPoint, ClampedStartTangent, EndPoint, ClampedEndTangent);
}
void ASplineTool::BeginPlay()
{
Super::BeginPlay();
}
void ASplineTool::Tick(float DeltaTime)
{
Super::Tick(DeltaTime);
/*
if (bEnableGrowth)
{
TimeSinceLastUpdate += DeltaTime;
if (TimeSinceLastUpdate > UpdateInterval)
{
ExtendSpline();
BaseSpline();
UE_LOG(LogTemp, Warning, TEXT("-----------"));
TimeSinceLastUpdate = 0;
}
}
*/
}