Hard references to interfaces are fine, especially for an interface that you will be using all the time like the interaction interface.
What I typically do is put an Interactable component on interactable actors, and an InteractionDetection overlap volume on the character. Then, in InteractionDetection OnBeginOverlap, I get the overlapping component, cast to Interactable interface, and get the text to display, and show the overlay GUI. I also remember the component that overlapped in a variable, that I clear in OnEndOverlap.
When the user presses E, if there’s a current saved interactable object, call that interface again with a “DoInteraction” message. That component will typically just use that message to invoke an event dispatcher, so the interactable component can be added to any actor, and the actor event graph can then hook up what to actually do during interaction.
So, the Interactable interface is:
GetInteractionText()
DoInteraction()
The InteractionComponent has variables for InteractionText
and an Event Dispatcher for Perform Interaction
that its actor can configure.
The player adds an overlapping Trigger Volume
hanging off the root (or sticking out the eyes, for an FPS,) poking out ahead, to detect things to interact with, and wires up On Begin Overlap
and On End Overlap
, as well as the GUI widget
to display the text, and the Input Action
to perform the interaction.
None of this needs “soft references” because the size of the involved components is minuscule, and the character and interaction doesn’t need to know about the concrete actor being interacted with at all.