is "FindComponentByClass<>()" expensive?

Dear experts,

I have a Character (derived from ACharacter) and I attached a HealthComponent (derived from UActorComponent) to it to keep track
of the Character health.

Now I have a Pickup (derived from AActor) that adds health points and I call a Heal() method like this:
On line 22 I get a reference to the HealthComponent of the Character to then call Heal() on line 30:

Now I read that “FindComponentByClass<>()” is an expensive thing to do. But what would be an alternative? How else
can I get a reference from my Pickup AActor to a UActorComponent of a ACharacter?

If I leave out line 22 the engine crashes when I overlap the Pickup with my Character.

Thank you, Peter

2 Likes

Usually, I would use FindComponentByClass<>() on actors that may or may not have the component I’m looking for (meaning the component isn’t standard to my class). But if you know that your AMainCharacter will always have a UHealthComponent, then make it a UHealthComponent* property on your AMainCharacter class and access it directly (or if you want to keep it a private member, add public accessors to its data) – no need to search all components for the one you’re looking for if you know it’s always supposed to be there.

2 Likes

This is extremely unlikely to have any measurable performance impact in the usage you showed.

I would also like to know which container is used for storing the actor components/actors. Personally I avoid using functions like these in tick-events or timers, but for a one-time-call it should’nt be too expensive.

This is very cheap because Epic guys are very clever (in Unity doing that is very expensive).

Unreal will do a “->IsA(…)” check before even casting anything in there.
Within IsA() method there’s a bunch of UE_ASSUME macros that speeds up things even further.

If your concern is bound to RAM (slow), Epic also provide us a workaround you can use inline with TInlineComponentArray<>:



TInlineComponentArray<UStaticMeshComponent*> SMComponets;
Actor->GetComponents<UStaticMeshComponent>(SMComponets);

for (UStaticMeshComponent* Component : SMComponets)
{
    // .....
}


https://docs.unrealengine.com/en-US/…ray/index.html

For custom types other than components you can also use custom allocators and specify the min size you expect, like:



TArray< FmyCustomType , TInlineAllocator<24> > myArray;


4 Likes

Hi, “OnComponentBeginOverlap” is defined in “APickupHealer” and is of what I understand only called when the PickupHealer is overlapped. So no Tick() is checking on it.

Thank you for this explanation. I will stick with my code then, I feel pretty comfortable.