Download

[SOLVED] SetLocationAtSplinePoint does not set the location

Hey guys.

I’m using USplineComponent to give the player the ability to construct conveyor lines within a factory. The flow for constructing a conveyor line, goes something like this:

  1. The player picks the conveyor line type they wish to construct
  2. We spawn the actor with the USplineComponent and construct meshes along the spline based on various variables
  3. The actor follows the cursor around, by setting the actor location SetActorLocation()
  4. When the player clicks LMB, we will no longer move the entire actor, but move the last spline point (spline point index 0)
  5. When the player clicks LMB, nothing will follow the cursor anymore, and the player has now constructed a conveyor line.

There is one step in the middle that I’d like the player to be able to do. That is raising and lowering the height of the conveyor, depending on what spline point we’re currently moving around. If we’re moving the entire actor, it’s spline point at index 0. If the player already clicked the LMB once, and therefore we’re only moving the last splint point index, it’s spline point index 1.

It should be said, that ew’re talking about runtime functionality for the USplineComponent. This is not in the editor, but rather during gameplay.

Consider the following function for raising (lowering is basically just the opposit on the Z axis)



void AConveyorLineNew::Raise()
{
int32 SplinePointToRaise = bInitialConstruct ? GetInitialConstructSplinePointToRaiseAndLower() : GetSplinePointToMove();
FVector CurrentSplinePointLocation = Spline->GetLocationAtSplinePoint(SplinePointToRaise, ESplineCoordinateSpace::Local);

// Create and add the elevation vector
FVector ElevationVector(0.f, 0.f, ElevationAmountPerStep);
FVector NewLocation = CurrentSplinePointLocation + ElevationVector;

// If we've reached the maximum height limit
if (NewLocation.Z > MaximumElevation)
return;

// Set the new location of the spline point that we're currently manipulating
Spline->SetLocationAtSplinePoint(SplinePointToRaise, NewLocation, ESplineCoordinateSpace::Local);

// Contruct meshes along the spline
ConstructMeshes();
}


This all seems to work fine for spline point at index 0. Now, when the user clicks LMB once, we should raise/lower the second spline point, at index 1. This is where it goes wrong. I debugged, logged, and checked everything, but the location of the spline point at index 1, won’t move at all, even though it should be raised 75 units on the Z axis.

I get no errors what so ever, it’s just as if the new location is not being set at the spline point index 1. If I hardcode to spline point index 0, both the raise as well as the lower function, works just fine. But it won’t let me alter the Z axis value for spline point at index 1.

Anyone know what’s happening here?


[void](https://docs.unrealengine.com/en-US/API/Runtime/OpenGLDrv/void/index.html) SetLocationAtSplinePoint
(
[int32](https://docs.unrealengine.com/en-US/API/Runtime/Core/HAL/int32/index.html) PointIndex,
    const [FVector](https://docs.unrealengine.com/en-US/API/Runtime/Core/Math/FVector/index.html) & InLocation,
[ESplineCoordinateSpace::Type](https://docs.unrealengine.com/en-US/API/Runtime/Engine/Components/ESplineCoordinateSpace__Type/index.html) CoordinateSpace,
[bool](https://docs.unrealengine.com/en-US/API/Runtime/LiveLinkInterface/bool/index.html) bUpdateSpline
)

Maybe add true at the end of the function call?

It’s defaulting to true. Besides, this would also be a problem for the first splint point, at index 0, if that was the case :slight_smile:

So index zero you can change but 1 you cannot? how about index 2 does that work?

Correct. index 0 works fine, index 1 does not. I only have 2 spline points by design

Its possible its a bug, I found an older post using blueprints complaining about the same thing. I haven’t used splines yet so I’m of no help. What happens if you try a different coordinate space does that do anything at all? (dont use local)

[Edit]
I found this:
https://github.com/carla-simulator/c…utePlanner.cpp

they are using world coordinate to move the spline points

Just tried it. Unfortunately no difference, but nice observation from your point :slight_smile:

Ok looking at source code from the engine now…

What value does this print out SplineCurves.Position.Points.Num() ?

I ask because here is the code from the engine, maybe you’re failing the check here:

It might not count start and end as 2 spline points, it might only count everything passed the initial spline point. If that is the case, then you can never modify the last spline point, and if you need to do that, you would have to make the spline not not be last, but be 2nd to last, so you would have to add an extra spline point.


void USplineComponent::SetLocationAtSplinePoint(int32 PointIndex, const FVector& InLocation, ESplineCoordinateSpace::Type CoordinateSpace, bool bUpdateSpline)
{
const int32 NumPoints = SplineCurves.Position.Points.Num();

if ((PointIndex >= 0) && (PointIndex < NumPoints))
{
const FVector TransformedLocation = (CoordinateSpace == ESplineCoordinateSpace::World) ?
GetComponentTransform().InverseTransformPosition(InLocation) : InLocation;

SplineCurves.Position.Points[PointIndex].OutVal = TransformedLocation;

if (bUpdateSpline)
{
UpdateSpline();
}
}
}


Found my issue.

The Raise and Lower methods modifies the Z value on the location. However, when the player is constructing a conveyor line, I’m altering the location of the conveyor line, each tick.
The following method was the one giving me issues:



void AConveyorLineNew::MoveToLocation(FVector Location)
{
    if (bInitialConstruct)
        SetActorLocation(Location);
    else
        Spline->SetLocationAtSplinePoint(GetSplinePointToMove(), Location, ESplineCoordinateSpace::World);
}


I need to first get the current location of the spline point, then set the Location.Z to the current Z value:



void AConveyorLineNew::MoveToLocation(FVector Location)
{
    if (bInitialConstruct)
        SetActorLocation(Location);
    else
    {
        // To support raising and lowering the conveyor, we must get the current location to find the value on the Z axis.
        FVector CurrentLocation = Spline->GetLocationAtSplinePoint(GetSplinePointToMove(), ESplineCoordinateSpace::World);
        Location.Z = CurrentLocation.Z;

        Spline->SetLocationAtSplinePoint(GetSplinePointToMove(), Location, ESplineCoordinateSpace::World);
    }
}


@ViperG: Thanks for the help. Really appreciate it!