Temporarily Adding Ticking ActorComponents to Actors

Hey there,
I’m looking for a method of temporarily adding a Timeline Component to an actor and having it tick. We’re also utilizing an object pool so that the Timeline Components don’t require reallocation whenever this occurs (the idea is a quick add, initialization, tick, complete, remove.) The basic methods of programmatically adding Actor Components to actors seem to focus on the actor creating its own instantiation of a template Actor Component, which we would like to avoid. I tried using AActor::AddInstanceComponent, but it doesn’t seem ‘instance components’ get registered for ticking, which is problematic.

For context, the situation is that I’m creating a derived AnimNotifyState implementation, which I’ve discovered is not able to hold any of its own state, as each AnimNotifyState is tied to the animation asset and not the instance. The attempt is to get the AnimNotifyState to interpolate the actor position while active. Since the AnimNotifyState is not given any state (ironic) context, using the UAnimNotifyState::NotifyTick is semi-useless, as I would have to find some nook or cranny on the object to stash my own state. This is the reason for the Timeline Component, to store the state and perform the tick, but herein the problem lies.

But the question is, what is/is there a proper method of adding a temporary ActorComponent to an Actor and have it be registered for tick?

Matt,

A lot of APIs require ownership, and this is true of Component Tick functions.

If you look, there’s actually a public function on UActorComponent’s called RegisterAllComponentTickFunctions. This is what’s used by AActor to setup the tick functions (typically done either when the component is created and registered, or once the Actor has BeginPlay called). These functions rely on the Actor owning the component however.

Luckily, we also expose ways to change ownership. It should be noted that you’ll have to be careful using these so you don’t accidentally cause your TimelineComponent to get garbage collected if the Actor dies while you think it should be ticking.

What you’ll probably end up doing is something like this:

void RegisterTImelineWithActor(UTimelineComponent* Timeline, AActor* Actor)
{
    // Might want to save this if it's not the TransientPackage / World.
    UObject* OriginalOwner = Timeline->GetOuter();
    FString OriginalName = Timeline->GetName();

    // We can leave the name alone.
    Timeline->Rename( *OriginalName, Actor );
    Actor->AddInstancedComponent(Timeline);
    Timeline->RegisterAllTickFunctions(true);

    // At this point, you can perform any other setup / re-initialization needed on the
    // timeline. Also, GetOwner in the Timeline should now return the passed in
    // Actor.
}

void UnregisterTimelineComponent(UTimelineComponent* Timeline)
{
    AActor* Actor = Timeline->GetOwner();
    
    // This will unregister tick functions.
    Timeline->RegisterAllTickFunctions(false);

    Actor->RemoveInstanceComponent(Timeline);

    FString OriginalName = Timeline->GetName();
    Timeline->Rename(*OriginalName, OriginalOuter);
}

Thanks,
Jon N.