Is it feasible to use delegates in the Tick() function?

In my ACharacter::Tick() function I’m broadcasting delegates as such:

UDELEGATE()
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnTickBP, ACharacter*, Character, float, DeltaTime);
DECLARE_MULTICAST_DELEGATE_TwoParams(FOnTick, ACharacter *, float );


FOnTickBP OnPreTickBP;
FOnTick OnPreTick;
FOnTickBP OnPostTickBP;
FOnTick OnPostTick;


void AMyCharacter::Tick(float DeltaTime){

    OnPreTick.Broadcast(this, DeltaTime);
    OnPreTickBP.Broadcast(this, DeltaTime);


    // ... Does stuff here


    OnPostTick.Broadcast(this, DeltaTime);
    OnPostTickBP.Broadcast(this, DeltaTime);
}

This is intentionally done to dynamically extend the functionality of the tick function from external sources

But is this feasible? Or will this cause severe performance issues? If so what alternatives should I look into?

Edit: Should I be using TFunctions instead? I tried the following and it seems to work with the only downside being incompatibility with Blueprints


TArray<TFunction<void(UAct*, float DeltaTime)>> ExtendedPreTicks;
TArray<TFunction<void(UAct*, float DeltaTime)>> ExtendedPostTicks;

void AMyCharacter::Tick(float DeltaTime){

    for (auto& PreTickFunc : ExtendedPreTicks) {
        PreTickFunc(this, DeltaTime);
    }


    // ... Does stuff here


    for (auto& PostTickFunc : ExtendedPostTicks) {
        PostTickFunc(this, DeltaTime);
    }
}

It will work, if that’s what you’re asking. It’s impossible to answer performance questions since it entirely depends on what is registered with those delegates and the type of work that gets done. It’s not a question that anyone can answer in the abstract. You can only profile and respond to the data it generates.

I can only say that it’s not a solution that’s ever come up as necessary in my experience making games with the engine. Adding a tickable component, deriving a new class type, registering with another ticking actor or registering with a ticking subsystem are all solutions I usually reach for.

But again, it will work in the way you’re intending.

1 Like

Well I’m binding relatively lightweight functions to the delegate since it does run every tick after all but my main concern is if or not delegates on their own are expensive to call?

and I did consider deriving new classes to extend the functionality but most extended changes are so minute that creating a separate class for them seemed unnecessary

but if it’s performance that’s at stake I can go for it, what would you recommend in the long run?

Also could you elaborate on “registering with a ticking subsystem” or perhaps an example if possible?

No. The expense is from what is being called, not the delegate.

To profile and fix the things that are slow in the profile. Other than that no one’s going to be able to say because only you understand the kinds of things you’re going to try to extend this way.

You can derive from UTickableWorldSubsystem or you can replicate that one using FTickableGameObject to make any subsystem tickable. Then you give it some functions to add and remove an Actor from a collection and you do the work on tick. Whatever code is deciding to add or remove from those delegates would instead add or remove from the subsystem. You do lose your pre/post tick behavior, but that’s probably better handled through the other tools available for tick ordering like tick groups.