UCurveFloat does not exist in binded function

Hello guys,

I’m passing a blueprint behaviour to C++ and in this case i need to handle two different CurveFloat variables like this:

For the first curve.

For the second one.

So, this this i created the next code:



    UCLASS()
    class SIDERUNNER_API ASideRunnerPaperCharacter : public APaperCharacter
    {
        GENERATED_BODY()

        FTimeline OnDeathRotation;
        FTimeline OnPlayRotation;

        FTimerHandle ShowGameOverScreenDelayHandler;
        FTimerHandle StopMovementDelayHandler;

        UPROPERTY()
        class UCurveFloat *DeathRotation = nullptr;

        UPROPERTY()
        class UCurveFloat *PlayRotation = nullptr;

        bool bDoubleJump;

        class ASideRunnerGameModeBase *Ref_GameMode = nullptr;

        class UTextRenderComponent *TextComponent = nullptr;

        void BeginPlay() override;
        virtual void Tick(float DeltaSeconds) override;

    protected:

For the header file: two CurveFloat pointers and two FTimeLine for use them.


     /* This is the way using a Blueprint Curve */
        static ConstructorHelpers::FObjectFinder<UCurveFloat> PlayCurve(TEXT("/Game/Blueprints/Utils/Curve_PlayRotation_Float"));
        check(PlayCurve.Succeeded());
        PlayRotation = PlayCurve.Object;

        static ConstructorHelpers::FObjectFinder<UCurveFloat> DeathCurve(TEXT("/Game/Blueprints/Utils/Curve_DeathRotation_Float"));
        check(DeathCurve.Succeeded());
        DeathRotation = DeathCurve.Object;

        /* This is the way creating the curve with code, it does not work for me
        PlayRotation = NewObject<UCurveFloat>();
        PlayRotation->FloatCurve.AddKey(0.0f, 0.0f);
        PlayRotation->FloatCurve.AddKey(1.0f, -360.0f);

        DeathRotation = NewObject<UCurveFloat>();
        DeathRotation->FloatCurve.AddKey(0.f, 0.f);
        DeathRotation->FloatCurve.AddKey(1.f, -512.f);
        */

        FOnTimelineFloat TimelineCallback;
        FOnTimelineEventStatic TimelineFinishedCallback;

        TimelineCallback.BindUFunction(this, "RotatePlayer");

        if (PlayRotation)
        {
            OnPlayRotation.AddInterpFloat(PlayRotation, TimelineCallback, TEXT("Player Rotation"));
            OnPlayRotation.SetLooping(true);
            OnPlayRotation.SetTimelineLength(1.f);
            OnPlayRotation.SetTimelineLengthMode(ETimelineLengthMode::TL_TimelineLength);
        }
        else
        {
            UE_LOG(LogTemp, Warning, TEXT("There is no Curvefloat Object here!"));
        }

        if (DeathRotation)
        {
            OnDeathRotation.AddInterpFloat(DeathRotation, TimelineCallback, TEXT("Death Rotation"));
            OnDeathRotation.SetLooping(true);
            OnDeathRotation.SetTimelineLength(1.f);
            OnDeathRotation.SetTimelineLengthMode(ETimelineLengthMode::TL_TimelineLength);
        }
        else
        {
            UE_LOG(LogTemp, Warning, TEXT("There is no DeathRotation curve here!"));
        }

This code for the constructor.



    void ASideRunnerPaperCharacter::RotatePlayer()
    {
        float TimelineValue;
        float RotationFloatValue;

        /* As whatever the status of the character (dead ot not) the rotation will be the same workflow,
            and as we just change the Curve values, we handle both rotation behaviour in the same function
            based on the character's status
        */
        if (bDeath)
        {
            TimelineValue = OnDeathRotation.GetPlaybackPosition();
            if (DeathRotation)
            {
                RotationFloatValue = DeathRotation->GetFloatValue(TimelineValue);
            }
            else
            {
                UE_LOG(LogTemp, Warning, TEXT("There is no such DeathRotation curve."));
            }
        } else
        {
            TimelineValue = OnPlayRotation.GetPlaybackPosition();

            if (PlayRotation)
            {
                RotationFloatValue = PlayRotation->GetFloatValue(TimelineValue);
            }
            else
            {
                UE_LOG(LogTemp, Warning, TEXT("There is no such PlayRotation curve."));
            }
        }

        GetSprite()->SetRelativeRotation(FRotator(RotationFloatValue, 0.f, 0.f));
    }

This is the function which rotates the sprite based on the timeline value.



    void ASideRunnerPaperCharacter::Tick(float DeltaSeconds)
    {
        Super::Tick(DeltaSeconds);

        if (OnPlayRotation.IsPlaying())
            OnPlayRotation.TickTimeline(DeltaSeconds);

        if (OnDeathRotation.IsPlaying())
            OnDeathRotation.TickTimeline(DeltaSeconds);
    }

Tick function for link the characters tick with the timeline time.


    void ASideRunnerPaperCharacter::BeginPlay()
    {
        // TODO: DeathRotation is being destriyed here
        Super::BeginPlay();

        UWorld *world = GetWorld();

        if (world)
        {
            Ref_GameMode = world->GetAuthGameMode<ASideRunnerGameModeBase>();
        }

        OnPlayRotation.Play();
    }

The begin play function when the OnPlayRotation timeline is launched.


    void ASideRunnerPaperCharacter::OnDeath()
    {
        if (!bDeath)
        {
            bDeath = true;
            SetActorEnableCollision(false);
            LaunchCharacter(FVector(0.f, 0.f, JumpVelocity * 2), true, true);

            // TODO: Here make another timeline for OnDeathRotation
            OnPlayRotation.Stop();
            OnDeathRotation.Play();

            // This does not work: GetWorld()->GetTimerManager().SetTimer(DelayHandler, 0.2f, false);
            GetWorld()->GetTimerManager().SetTimer(ShowGameOverScreenDelayHandler, this, &ASideRunnerPaperCharacter::ShowGameOverScreen, 2.5f);

            GetWorld()->GetTimerManager().SetTimer(StopMovementDelayHandler, this, &ASideRunnerPaperCharacter::StopMovement, 4.f);
        }
    }

And finally, the function when the second timeline must to be launched.

At launche the editor both CurveFloat are created correctly:

But after the begin play it is nullified:

After finishing the game and relaunch it:

And after begin play i have the same error again, i tried to sovle it playing the second timeline in the BeginPlay function but it also didn’t work.

So, what’s is my mistake here?
Thank you very much for your help.

Usually when this happens is because you are doing TOO much in the constructor.
Constructor you typically only do minimal or required setup only.

extra stuff, you would need to do in begin play.

Someone with more experience might need to chime in on the specifics of what you need to move out of the constructor into begin play. Or you can just start test moving stuff until your data is no longer cleared/nulled out.

Good information, thanks, how did you learn it? I didn’t found any information like that.

The C++ Constructor is very different to the construction script and much lower-level (and they do run during gameplay, they in fact run anytime you instantiate one of those objects in memory).

You do have to be careful what you do in there. Constructors are for initialization only, you shouldn’t be doing any complex logic or trying to reference other classes and objects aside from creating Sub-Objects.

The Blueprint Construction Script equivalent in C++ is OnConstruction(), which you can override on Actors and do more setup if you need to, but really PostInitializeComponents() and BeginPlay() are probably the only things you need. Actor.h has a very long description at the top of the class as to what runs when, and what you should use each function for.

To be honest, Timelines are also kind of a wierd thing to use in C++ - they have an editor tool all of their own for a reason. There’s nothing to say you can’t use them, but it’s like trying to write an entire UMG interface with components in C++ when you have the UMG Editor. As a rule of thumb - if the editor has a bespoke tool for something, you should probably use it that way.

I can’t believe I really came to that conclusion a few hours ago. It is the blueprint construction script that runs in the editor but cooks when you package the game. I think. I’m getting a lot of conflicting information online about it.