Is FindComponentByClass the preferred way to test if a given component is on a given actor?

I’m trying to curate an array of interactable objects within range of the player by checking each object they approach via OnOverlap, and testing whether they actually have one of the many subclasses of the InteractionBase class which outlines rules for all interactables. Right now I’ve been clunkily trying to get FindComponentByClass to work, the assumption being that if it returns null, the given actor doesn’t have that component:



UInteractionBase* interactable = characterPerception->attentionTarget->FindComponentByClass(UInteractionBase::StaticClass());
if (interactable != nullptr){
interactableList.Add(characterPerception->attentionTarget);
}

Once I figure out the syntax problem in the first line, is this the recommended way to go about things? Or does the API have something meant explicitly to test for the presence of a component class instead of just trying to set it?

Personally I think this approach is fine. I like the fact that you only do these checks in OnOverlap events.

An alternative that I can think of is making actor C++ classes inherit a interactable UInterface/IInterface. However, that won’t work if you want to be able to make an actor interactable on the fly by adding a component, whereas this does. I’d stick with this! Finally if you’re going to do this check many times, it may help for each interactable actor to do this FindComponentByClass once at BeginPlay and storing the result so that the work only needs to be done once (and whenever a new component is added).

Hmm okay, thank you! I don’t know if it’s possible to constrain the behaviour by actor, since one of my reasons for doing it this way is to let me attach interaction components to otherwise generic actors and meshes, which won’t have a framework to retain that value by default. :slight_smile:

You need to either cast the result of the call:


UInteractionBase* interactable = Cast< UInteractionBase >(characterPerception->attentionTarget->FindComponentByClass(UInteractionBase::StaticClass()));

or, more cleanly, use the templated version:


UInteractionBase* interactable = characterPerception->attentionTarget->FindComponentByClass< UInteractionBase >();

I don’t think you can use any Actor functionality to store the component beforehand, well unless you count storing a tag “IsInteractable” on the actor. You could use that to quickly eliminate actors that aren’t interactable. However when it is interactable you will still need to get the component.

Another idea is to make a dictionary, in this case TMap<AActor*, UInteractionBase*>, in some central actor like game mode or game state. Make every interactable add its owning actor and itself to the TMap. Then at run-time for any actor you can check whether it is in the TMap and get its corresponding interaction component if it is.