Procedural Spline-based Road Creation

So, I’m following along with this great tutorial:

[Tutorial][1]

The problem is that it seems to work when I do all the node hookups in the construction script. The SplineMesh is generated as expected more or less.

However, I’m building my road splines procedurally in c++ first. The splines are created, then the resulting spline is sent into a blueprint script to generate the splinemesh component. So, the SplineMeshes can’t be created in the construction script. But when I run the code in that layout, the SplineMeshes do not appear to generate.

Is there any reason the SplineMeshComponent would misbehave in this way?

My Blueprint that calls the function that builds the SplineMesh :

The spline that has been generated by code, but no accompanying SplineMeshes:

The blueprint to create the SplineMesh based on the tutorial:

If anyone is interested, I just re-wrote some the basics of it in code, and it seems to work. Might have something to do with the RegisterAllComponents() call at the end, because if I leave that out, it doesn’t build the static mesh, similar to how it wasn’t building in BluePrint;

The InRoadSpline array at the beginning is just an array of vectors of each path that is built by my map generator, and the tileSize is the multiplier for the tiles of the map.

RoadDataArray is a struct that is mentioned in the video linked above to hold values for each tile’s bank, thickness, and width;

If anything looks weird, or could be done better, feel free to give suggestions. I’m just learing c++ and culling together information from everywhere I can find it.

EDIT: having trouble with board markup, never used this before

void ARoadSpline::BuildRoadSpline(TArray InRoadSpline, int32 tileSize)
    {
    	FVector tileMultiplier(tileSize, tileSize, 1);
    
    	if (InRoadSpline.Num() >= 2)
    	{
    		//the first 2 points are created automatically, set them manually
    		RoadSplineComp->SetWorldLocationAtSplinePoint(0, InRoadSpline[0] * tileMultiplier);
    		RoadSplineComp->SetWorldLocationAtSplinePoint(1, InRoadSpline[1] * tileMultiplier);
    
    		//set the remaining points if they exist
    		for (int32 i = 2; i < InRoadSpline.Num(); i++)
    		{
    			RoadSplineComp->AddSplineWorldPoint(InRoadSpline[i] * tileMultiplier);
    		}
    	}
    }

void ARoadSpline::BuildRoad()
{
//set the spline point counter to be equal to the number of spline points
NumSplinePts = RoadSplineComp->GetNumSplinePoints();

    	//make RoadDataArray the same length as the spline points
    	if (RoadDataArray.Num() < NumSplinePts)
    	{
    		for (int32 i = 0; i < NumSplinePts; i++)
    		{
    			RoadDataArray.Add(FRoadSplineData(0, 1, 1));
    		}
    	}
    
    	else if (NumSplinePts < RoadDataArray.Num())
    	{
    		for (int32 i = RoadDataArray.Num(); i > NumSplinePts; i--)
    		{
    			RoadDataArray.Remove(RoadDataArray.Last());
    		}
    	}
    
    	BuildRoadMesh(RoadMesh);
    
    }

void ARoadSpline::BuildRoadMesh(UStaticMesh* inStaticMesh)
{
for (int32 i = 0; i < NumSplinePts - 1; i++)
{
/*
*
*initialize local variables
*
*/
int32 _currentLoopIndex(i);
int32 _nextLoopIndex((i + 1));

    		UStaticMesh* _StaticMesh = inStaticMesh;
    
    		//set the Start location and tangent of the spline current location
    		FVector _startLocation;
    		FVector _startTangent;
    		RoadSplineComp->GetLocalLocationAndTangentAtSplinePoint(_currentLoopIndex, _startLocation, _startTangent);
    
    		//set the End location and tangent of the spline current location
    		FVector _endLocation;
    		FVector _endTangent;
    		RoadSplineComp->GetLocalLocationAndTangentAtSplinePoint(_nextLoopIndex, _endLocation, _endTangent);
    
    		//set the startRoll, and startScale
    		float _startRoll(RoadDataArray[_currentLoopIndex].TrackBank);
    		FVector2D _startScale(RoadDataArray[_currentLoopIndex].TrackWidth, RoadDataArray[_currentLoopIndex].TrackThickness);
    
    		//set the startRoll, and startScale
    		float _endRoll(RoadDataArray[_nextLoopIndex].TrackBank);
    		FVector2D _endScale(RoadDataArray[_nextLoopIndex].TrackWidth, RoadDataArray[_nextLoopIndex].TrackThickness);
    
    
    		/*
    		*
    		*start building the road
    		*
    		*/
    		USplineMeshComponent* _splineMesh = ConstructObject<USplineMeshComponent>(USplineMeshComponent::StaticClass(), this);
    
    		_splineMesh->CreationMethod = EComponentCreationMethod::UserConstructionScript;
    
    		_splineMesh->SetMobility(EComponentMobility::Movable);
    		_splineMesh->AttachParent = RoadSplineComp;
    
    		_splineMesh->SetStaticMesh(inStaticMesh);
    
    		_splineMesh->SetStartScale(_startScale);
    		_splineMesh->SetEndScale(_endScale);
    
    		_splineMesh->SetStartRoll(_startRoll);
    		_splineMesh->SetEndRoll(_endRoll);
    
    		_splineMesh->SetStartAndEnd(_startLocation, _startTangent, _endLocation, _endTangent);
    	}
    
    	RegisterAllComponents();
    }

ConstructObject is deprecated in 4.9 and the errors will tell you use to New Object instead. For Example :

USplineMeshComponent* SplineMesh = NewObject(this, USplineMeshComponent::StaticClass());

Hey there, I’m trying to achieve something like the ghost recon wildlands road system (which procedurally generates paths that become roads) and this is the closest result I have found… so if you could tell me if it is working properly and also you opinion about other ways that I searched to achieve this (because I’m new in programming) it would help me a lot, thanks