Has anybody actually managed to get Timelines working in C++?

I want to implement a simple function that fires a Timeline from Start > Finish, and the Float value along the Timeline is sent to another function.

I can’t find any examples anywhere of how to implement this, and the documentation isn’t helping me. The only thing I’ve found on the subject so far is this, but none of the parameters he is passing in are explained, and FOnTimelineFloat doesn’t seem to exist.

Does anybody actually have these working? Most people I’ve seen asking about this have just gone back to using FInterpTo and not using a curve.

Whats wrong with using a data curve for it? I used FloatCurve (miscellaneous->curve in the editor data type) and used that for interpolation (pass in elapsed time, get back float). Why would you need timeline, unless you want to animate other properties together with it?

How about looking at the blueprint interface for Timeline and seeing how it uses them?

Basically what I wanted to do was just tell the Timeline “Play From The Start”, with just a one-time call that would manage it.

Instead I’ve had to create a Timer that re-calls the function until the Time has elapsed, passing the time in and getting the value along the curve. Isn’t there a TimeLine manager of some kind similar to Timers that handles the playback of them?

Hi!

I have the same need, did you manage to find a decent way to do that ? Handling the Ticking of the Timeline manually is really annoying…

I’m using a simeple c++ implemented timeline for a door that can be opened/closed which is based on the link u posted.
The FOnTimelineFloat is part of the engine, so should be available (FOnTimelineFloat | Unreal Engine Documentation)

Header file:



// Copyright 2015 Deborggraeve Randy. All Rights Reserved.

#pragma once

#include "Interaction/SwatUsableActor.h"
#include "SwatDoor.generated.h"

UCLASS()
class ASwatDoor : public ASwatUsableActor
{
public:
	GENERATED_BODY()
	
public:
	/* Sets default values for the properties */
	ASwatDoor(const FObjectInitializer& ObjectInitializer);

	/** Update the properties. */
	virtual void Tick(float DeltaSeconds) override;

	/** Starts interacting with the object */
	virtual void StartInteract() override;

	/** Returns true if the object is currently interactable */
	virtual bool CanInteract() override;

	/** Returns the name of the interaction */
	virtual const FString GetInteractionName() override;

	/** Function which gets called from the Timeline on a Tick */
	UFUNCTION()
	void AnimationEffectProgress(float Value);

public:
	/** Timeline for the effectprogress*/
	FTimeline AnimationTimeLine;

	/** Rotate the door to the other side */
	UPROPERTY(EditAnywhere, Category = "Animation")
	bool bInverseRotation;

	/** Current state of the door */
	bool bIsOpen;
	
};



Source file:



// Copyright 2015 Deborggraeve Randy. All Rights Reserved.

#include "SwatReloaded.h"
#include "SwatDoor.h"

ASwatDoor::ASwatDoor(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer)
{
	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	// Setup the animation
	const ConstructorHelpers::FObjectFinder<UCurveFloat> Curve(TEXT("/Game/Animations/Curves/DoorRotationCurve"));
	AnimationTimeLine = FTimeline{};
	FOnTimelineFloat progressFunction{};
	progressFunction.BindUFunction(this, "AnimationEffectProgress");
	AnimationTimeLine.AddInterpFloat(Curve.Object, progressFunction, FName{ TEXT("EFFECTFADE") });

	// Set the initial state
	bIsOpen = false;
}

void ASwatDoor::Tick(float DeltaSeconds)
{
	if (AnimationTimeLine.IsPlaying())
	{
		AnimationTimeLine.TickTimeline(DeltaSeconds);
	}
}

void ASwatDoor::StartInteract()
{
	if (!AnimationTimeLine.IsPlaying())
	{
		if (bIsOpen)
		{
			bIsOpen = false;
			AnimationTimeLine.Reverse();
		}
		else
		{
			bIsOpen = true;
			AnimationTimeLine.Play();
		}
	}
}

bool ASwatDoor::CanInteract()
{
	return bInteractable && !AnimationTimeLine.IsPlaying();
}

const FString ASwatDoor::GetInteractionName()
{
	if (bIsOpen)
	{
		return TEXT("Close Door");
	}
	else
	{
		return TEXT("Open Door");
	}
}

void ASwatDoor::AnimationEffectProgress(float Value)
{
	FRotator Rotation(0.0f, bInverseRotation ? -Value : Value, 0.0f);
	SetActorRelativeRotation(Rotation);
}


1 Like

Nice post Fallonsnest :slight_smile: Might add that to the Wiki at some point if you don’t mind…

Please do add to wiki :slight_smile:

Still learning UE4 so i also gota search most of time to get things working. So if the code is usefull to others, i’m happy to share it.

I have a little update on this as there is still some very old answers on answerhub which uses tick function from actor and other stuff etc. which gives some confusion about why to actually use timeline in the first place.

You can find an example here:

https://answers.unrealengine.com/questions/384597/link-to-timelines-doc-for-c.html

I took my freedom to add a wiki here:

This works great in single-player games.

Any idea how to make things work in multiplayer games?
How to replicate the timeline and its function calls using C++? :slight_smile:

Updated: Apparently, Timelines aren’t supposed to be replicated: they need to be started on each client independently.

I’m probably missing something here. Without the Tick() function?

I’m using AddInterpFloat() with a bound UFunction, can’t make it work without TickTimeline() :frowning:

Hi :slight_smile:

I hope I didnt put some wiki up with something that doesn’t drive :slight_smile:

I just tested it again on my side on 4.10 and it the timeline flows. Where do you call Play() or PlayFromStart()? Play() activates the tick of the timeline component. U don’t need to call TickTimeline() yourself. Try to put AddInterpFloat() at Begin Play or anywhere else outside the constructor if you haven’t done so already.

Hello :smiley:

On the constructor, I have:


	static ConstructorHelpers::FObjectFinder<UCurveFloat> SpawnEffectBuildPhaseCurveObject(TEXT("CurveFloat'/Game/Haven/Environment/Blocks/Materials/Timeline/Curve_SpawnEffectBuildPhase.Curve_SpawnEffectBuildPhase'"));
	SpawnEffectBuildPhaseCurve = SpawnEffectBuildPhaseCurveObject.Object;

On StartSpawnEffect() I have:


	FOnTimelineFloat UpdateEffectFunction;
	UpdateEffectFunction.BindUFunction(this, FName("UpdateSpawnEffect"));

	SpawnTimeline.AddInterpFloat(SpawnEffectBuildPhaseCurve, UpdateEffectFunction);
	SpawnTimeline.SetLooping(false);
	SpawnTimeline.PlayFromStart();


This is called when the state of my actor is changed to “Spawning” with an OnRep_ function

On UpdateSpawnEffect() I have:


	BlockMaterialInstanceDynamic->SetScalarParameterValue("MaterializedAmount", Value);

I can’t make it work without having inside the Actor’s Tick() function:


	Super::Tick(DeltaTime);

	// Zoc (2016-04-05): Update our spawn effect, if it's happening.
	if (SpawnTimeline.IsPlaying())
		SpawnTimeline.TickTimeline(DeltaTime);

And… it would be great if I could remove that Tick() from there, since the only thing it does is to make the timeline execute fully once. :frowning:

I assure you that the actor doesn’t tick where I added the timeline :smiley:

Try the following:

  • Initialize your Timeline component in the constructor like it is in the wiki

  • Put the AddInterpFloat at BeginPlay for once.

  • Put the BindUFuntion and FOnTimelineFloat in the constructor

  • Maybe put your return function (UpdateSpawnEffect() ) under protected in the header file

I’m sorry!

I was using [FONT=Courier New]FTimeline instead of [FONT=Courier New]UTimelineComponent* :frowning:

After I changed, it worked without the Tick() function.

I’m probably very tired and I ended up missing this, I’m sorry. Your guide is solid :smiley:
Thank you for your guide!

Btw, if it help anyone out there, using [FONT=Courier New]UTimelineComponent* and initializing it on the constructor is enough to make it work without the tick function, apparently (I haven’t tested thoroughly, but it’s working on my setup :slight_smile: ).

I should probably get some sleep now :slight_smile:

I couldn’t make it work, and i got this error: UCurveFloat does not exist in binded function - Character & Animation - Unreal Engine Forums

How could you solve it?