I set a timer loop using an actor. I don’t know why, but it stops calling the call-back function without any reasons and error messages.
I have a timeline object and create a timer function to loop the FTimeline.
/**
* UKTimelineObject holds a FTimeline.
* Events can be triggered at keyframes along the timeline.
* Floats, vectors, and colors are interpolated between keyframes along the timeline.
*/
UCLASS()
class UKTimelineObject : public UObject
{
GENERATED_UCLASS_BODY()
public:
/**
* @brief Initializes the timeline with a vector curve and set the tick and finish call-back functions.
*
* @param VectorCurve If non-null, the vector curve.
* @param TickFunc The function to call on every tick.
* @param FinishedFunc The finished function.
* @param InOwner The actor owner.
* @param InDeltaTime (Optional) the delta time between the play rate value. Default is 1.0
* @param InPlayRate (Optional) the play rate. Default is 1.0
* @param InLengthMode (Optional) the in length mode. Default is ETimelineLengthMode::TL_TimelineLength.
* @param InLength (Optional) the initial length. Default is 100.
* @param PropertyName (Optional) name of the property. Default is NAME_None.
*/
void Initialize(UCurveVector* VectorCurve, FOnTimelineVector TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime = 1.0f, float InPlayRate = 1.0f, ETimelineLengthMode InLengthMode = ETimelineLengthMode::TL_TimelineLength, const float InLength = 100.0f, FName PropertyName = NAME_None);
/**
* @brief Initializes the timeline with a float curve and set the tick and finish call-back functions.
*
* @param FloatCurve If non-null, the float curve.
* @param TickFunc The function to call on every tick.
* @param FinishedFunc The finished function.
* @param InOwner The actor owner.
* @param InDeltaTime (Optional) the delta time between the play rate value. Default is 1.0
* @param InPlayRate (Optional) the play rate. Default is 1.0
* @param InLengthMode (Optional) the in length mode. Default is ETimelineLengthMode::TL_TimelineLength.
* @param InLength (Optional) the initial length. Default is 100.
* @param PropertyName (Optional) name of the property. Default is NAME_None.
*/
void Initialize(UCurveFloat* FloatCurve, FOnTimelineFloat TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime = 1.0f, float InPlayRate = 1.0f, ETimelineLengthMode InLengthMode = ETimelineLengthMode::TL_TimelineLength, const float InLength = 100.0f, FName PropertyName = NAME_None);
/**
* @brief Initializes the timeline with a linear color curve and set the tick and finish call-back functions.
*
* @param LinearColorCurve If non-null, the linear color curve.
* @param TickFunc The function to call on every tick.
* @param FinishedFunc The finished function.
* @param InOwner The actor owner.
* @param InDeltaTime (Optional) the delta time between the play rate value. Default is 1.0
* @param InPlayRate (Optional) the play rate. Default is 1.0
* @param InLengthMode (Optional) the in length mode. Default is ETimelineLengthMode::TL_TimelineLength.
* @param InLength (Optional) the initial length. Default is 100.
* @param PropertyName (Optional) name of the property. Default is NAME_None.
*/
void Initialize(UCurveLinearColor* LinearColorCurve, FOnTimelineLinearColor TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime = 1.0f, float InPlayRate = 1.0f, ETimelineLengthMode InLengthMode = ETimelineLengthMode::TL_TimelineLength, const float InLength = 100.0f, FName PropertyName = NAME_None);
/** Start playback of timeline */
void Play();
/** Start playback of timeline from the start */
void PlayFromStart();
/** Start playback of timeline in reverse */
void Reverse();
/** Start playback of timeline in reverse from the end */
void ReverseFromEnd();
/** Stop playback of timeline */
void Stop();
/** Get whether this timeline is playing or not. */
bool IsPlaying() const;
/** Get whether we are reversing or not */
bool IsReversing() const;
/** Jump to a position in the timeline. If bFireEvents is true, event functions will fire, otherwise will not. */
void SetPlaybackPosition(float NewPosition, bool bFireEvents);
/** Get the current playback position of the Timeline */
float GetPlaybackPosition() const;
/** true means we whould loop, false means we should not. */
void SetLooping(bool bNewLooping);
/** Get whether we are looping or not */
bool IsLooping() const;
/** Sets the new play rate for this timeline */
void SetPlayRate(float NewRate);
/** Get the current play rate for this timeline */
float GetPlayRate() const;
/**
* @brief Sets the delta time between play rate for this timeline.
* @param NewDeltaTime The new delta time.
*/
void SetDeltaTime(float NewDeltaTime);
/** Get the current delta time between play rate for this timeline */
float GetDeltaTime() const;
/** Set the new playback position time to use */
void SetNewTime(float NewTime);
/** Get length of the timeline */
float GetTimelineLength() const;
/** Set length of the timeline */
void SetTimelineLength(float NewLength);
/** Sets the length mode of the timeline */
void SetTimelineLengthMode(ETimelineLengthMode NewLengthMode);
/** Get the initial length of the timeline */
float GetInitialTimelineLength() const;
/**
* @brief Sets initial timeline length.
* @param InLength The new initial time length.
*/
void SetInitialTimelineLength(const float InLength);
/** @brief Sets back the timeline length to initial length. */
void SetTimelineLengthToInitial();
UFUNCTION()
void OnRep_Timeline();
/** Add a callback event to the timeline */
void AddEvent(float Time, FOnTimelineEvent EventFunc);
/** Add a vector interpolation to the timeline */
void AddInterpVector(UCurveVector* VectorCurve, FOnTimelineVector InterpFunc, FName PropertyName = NAME_None);
/** Add a float interpolation to the timeline */
void AddInterpFloat(UCurveFloat* FloatCurve, FOnTimelineFloat InterpFunc, FName PropertyName = NAME_None);
/** Add a linear color interpolation to the timeline */
void AddInterpLinearColor(UCurveLinearColor* LinearColorCurve, FOnTimelineLinearColor InterpFunc, FName PropertyName = NAME_None);
/** Optionally provide an object to automatically update properties on */
void SetPropertySetObject(UObject* NewPropertySetObject);
/** Set the delegate to call after each timeline tick */
void SetTimelinePostUpdateFunc(FOnTimelineEvent NewTimelinePostUpdateFunc);
/** Set the delegate to call when timeline is finished */
void SetTimelineFinishedFunc(FOnTimelineEvent NewTimelineFinishedFunc);
/** Set the delegate to call when timeline is finished */
void SetDirectionPropertyName(FName DirectionPropertyName);
/** Get all curves used by the Timeline
void GetAllCurves(TSet<class UCurveBase*>& InOutCurves) const;
*/
private:
/**
* @brief Activates the timer for ticking the timeline.
*/
void Activate();
/**
* @brief Deactivates the timer for ticking the timeline.
*/
void Deactivate();
/**
* @brief Timer timeline on tick call-back.
*/
void TimerTimelineTick();
private:
/** The actual timeline structure */
UPROPERTY(ReplicatedUsing = OnRep_Timeline)
FTimeline TheTimeline;
/** @brief The initial timeline length. */
float InitialTimelineLength;
/** @brief The delta time used for ticking the timeline. */
float DeltaTime;
/** @brief Handle of the timer for ticking the timeline. */
FTimerHandle TimerTimelineHandle;
/** @brief The actor owning this timeline object. Needed to access the GetWorlTimerManager(). */
const AActor* TheActor;
};
UKTimelineObject::UKTimelineObject(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
, InitialTimelineLength(5.0f)
, DeltaTime(0.2f)
, TheActor(nullptr)
{
}
void UKTimelineObject::Initialize(UCurveVector* VectorCurve, FOnTimelineVector TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime, float InPlayRate, ETimelineLengthMode InLengthMode, const float InLength, FName PropertyName)
{
TheTimeline.AddInterpVector(VectorCurve, TickFunc, PropertyName);
TheTimeline.SetTimelineFinishedFunc(FinishedFunc);
TheTimeline.SetTimelineLengthMode(InLengthMode);
DeltaTime = InDeltaTime;
SetPlayRate(InPlayRate);
TheActor = InOwner;
SetInitialTimelineLength(InLength);
}
void UKTimelineObject::Initialize(UCurveFloat* FloatCurve, FOnTimelineFloat TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime, float InPlayRate, ETimelineLengthMode InLengthMode, const float InLength, FName PropertyName)
{
TheTimeline.AddInterpFloat(FloatCurve, TickFunc, PropertyName);
TheTimeline.SetTimelineFinishedFunc(FinishedFunc);
TheTimeline.SetTimelineLengthMode(InLengthMode);
DeltaTime = InDeltaTime;
SetPlayRate(InPlayRate);
TheActor = InOwner;
SetInitialTimelineLength(InLength);
}
void UKTimelineObject::Initialize(UCurveLinearColor* LinearColorCurve, FOnTimelineLinearColor TickFunc, FOnTimelineEvent FinishedFunc, const AActor* InOwner, float InDeltaTime, float InPlayRate, ETimelineLengthMode InLengthMode, const float InLength, FName PropertyName)
{
TheTimeline.AddInterpLinearColor(LinearColorCurve, TickFunc, PropertyName);
TheTimeline.SetTimelineFinishedFunc(FinishedFunc);
TheTimeline.SetTimelineLengthMode(InLengthMode);
DeltaTime = InDeltaTime;
SetPlayRate(InPlayRate);
TheActor = InOwner;
SetInitialTimelineLength(InLength);
}
void UKTimelineObject::Activate()
{
UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::Activate: DeltaTime=%f"), DeltaTime);
if (TheActor && !TimerTimelineHandle.IsValid())
TheActor->GetWorldTimerManager().SetTimer(TimerTimelineHandle, this, &UKTimelineObject::TimerTimelineTick, DeltaTime, true, 0.0f);
else
{
UE_LOG(LogDebug, Warning, TEXT("UKTimelineObject::Activate: TimerTimelineHandle is already running"));
}
}
void UKTimelineObject::Deactivate()
{
UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::Deactivate: ClearTimer"));
if (TheActor)
{
TheActor->GetWorldTimerManager().ClearTimer(TimerTimelineHandle);
}
TimerTimelineHandle.Invalidate();
}
void UKTimelineObject::TimerTimelineTick()
{
if (TheTimeline.IsPlaying())
{
UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::TimerTimelineTick: GetTimelineLength=%f GetPlayRate=%f GetPosition=%f DeltaTime=%f"), GetTimelineLength(), GetPlayRate(), GetPlaybackPosition(), GetDeltaTime());
TheTimeline.TickTimeline(GetPlayRate());
}
else
{
UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::TimerTimelineTick: Deactivate"));
Deactivate();
}
}
void UKTimelineObject::Play()
{
UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::Play"));
Activate();
TheTimeline.Play();
}
void UKTimelineObject::PlayFromStart()
{
UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::PlayFromStart"));
Activate();
TheTimeline.PlayFromStart();
}
void UKTimelineObject::Reverse()
{
UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::Reverse"));
Activate();
TheTimeline.Reverse();
}
void UKTimelineObject::ReverseFromEnd()
{
UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::ReverseFromEnd"));
Activate();
TheTimeline.ReverseFromEnd();
}
void UKTimelineObject::Stop()
{
UE_LOG(LogDebug, VeryVerbose, TEXT("UKTimelineObject::Stop"));
TheTimeline.Stop();
}
bool UKTimelineObject::IsPlaying() const
{
return TheTimeline.IsPlaying();
}
void UKTimelineObject::AddEvent(float Time, FOnTimelineEvent Event)
{
TheTimeline.AddEvent(Time, Event);
}
void UKTimelineObject::AddInterpVector(UCurveVector* VectorCurve, FOnTimelineVector InterpFunc, FName PropertyName)
{
TheTimeline.AddInterpVector(VectorCurve, InterpFunc, PropertyName);
}
void UKTimelineObject::AddInterpFloat(UCurveFloat* FloatCurve, FOnTimelineFloat InterpFunc, FName PropertyName)
{
TheTimeline.AddInterpFloat(FloatCurve, InterpFunc, PropertyName);
}
void UKTimelineObject::AddInterpLinearColor(UCurveLinearColor* LinearColorCurve, FOnTimelineLinearColor InterpFunc, FName PropertyName)
{
TheTimeline.AddInterpLinearColor(LinearColorCurve, InterpFunc, PropertyName);
}
void UKTimelineObject::SetPlaybackPosition(float NewPosition, bool bFireEvents)
{
TheTimeline.SetPlaybackPosition(NewPosition, bFireEvents);
}
float UKTimelineObject::GetPlaybackPosition() const
{
return TheTimeline.GetPlaybackPosition();
}
void UKTimelineObject::SetLooping(bool bNewLooping)
{
TheTimeline.SetLooping(bNewLooping);
}
bool UKTimelineObject::IsLooping() const
{
return TheTimeline.IsLooping();
}
bool UKTimelineObject::IsReversing() const
{
return TheTimeline.IsReversing();
}
void UKTimelineObject::SetPlayRate(float NewRate)
{
TheTimeline.SetPlayRate(NewRate);
}
float UKTimelineObject::GetPlayRate() const
{
return TheTimeline.GetPlayRate();
}
void UKTimelineObject::SetDeltaTime(float NewDeltaTime)
{
DeltaTime = NewDeltaTime;
}
float UKTimelineObject::GetDeltaTime() const
{
return DeltaTime;
}
void UKTimelineObject::SetNewTime(float NewTime)
{
TheTimeline.SetNewTime(NewTime);
}
float UKTimelineObject::GetTimelineLength() const
{
return TheTimeline.GetTimelineLength();
}
void UKTimelineObject::SetTimelineLength(float NewLength)
{
return TheTimeline.SetTimelineLength(NewLength);
}
void UKTimelineObject::SetTimelineLengthMode(ETimelineLengthMode NewLengthMode)
{
TheTimeline.SetTimelineLengthMode(NewLengthMode);
}
float UKTimelineObject::GetInitialTimelineLength() const
{
return InitialTimelineLength;
}
void UKTimelineObject::SetInitialTimelineLength(const float InLength)
{
InitialTimelineLength = InLength;
SetTimelineLengthToInitial();
}
void UKTimelineObject::SetTimelineLengthToInitial()
{
SetTimelineLength(InitialTimelineLength);
}
void UKTimelineObject::SetPropertySetObject(UObject* NewPropertySetObject)
{
TheTimeline.SetPropertySetObject(NewPropertySetObject);
}
void UKTimelineObject::SetTimelinePostUpdateFunc(FOnTimelineEvent NewTimelinePostUpdateFunc)
{
TheTimeline.SetTimelinePostUpdateFunc(NewTimelinePostUpdateFunc);
}
void UKTimelineObject::SetTimelineFinishedFunc(FOnTimelineEvent NewTimelineFinishedFunc)
{
TheTimeline.SetTimelineFinishedFunc(NewTimelineFinishedFunc);
}
void UKTimelineObject::SetDirectionPropertyName(FName DirectionPropertyName)
{
TheTimeline.SetDirectionPropertyName(DirectionPropertyName);
}
/* Linker error. Can't find TheTimeline.GetAllCurves.
void UKTimelineObject::GetAllCurves(TSet<class UCurveBase*>& InOutCurves) const
{
TheTimeline.GetAllCurves(InOutCurves);
}
*/
void UKTimelineObject::OnRep_Timeline()
{
}
void UKTimelineObject::GetLifetimeReplicatedProps(TArray< FLifetimeProperty > & OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
DOREPLIFETIME(UKTimelineObject, TheTimeline);
}
I initialize the object using the player character (AActor)
UKTimelineObject* Timeline = NewObject<UKTimelineObject>(UKTimelineObject::StaticClass());
Timeline->SetFlags(RF_MarkAsRootSet); // Not garbage collected
if (TemporaryUpDownCurve)
{
FOnTimelineFloat OnTick;
OnTick.BindUFunction(this, "TempEnergyDecayRateFactorTimelineTick");
FOnTimelineEvent OnFinish;
OnFinish.BindUFunction(this, "TempEnergyDecayRateFactorTimelineFinish");
Timeline->Initialize(TemporaryUpDownCurve, OnTick, OnFinish, this);
bCreated = true;
}
When I start the object, it ticks several times (not always the same occurrences) and stops calling the UKTimelineObject::TimerTimelineTick()
I don’t know if someone faced the same problem with looping timer ?
Txs.
D.