1
\$\begingroup\$

I have a class of objects tagged as interactables that my player can interact with when within range.

When my player is near them, I want to display a button prompt at the bottom of the screen, along with a description of the type of interaction possible (for example, "inspect", "use", etc.).

I want to account for the possibility that the player might be within range of two or more of them at once, and thus allow him to toggle through them, displaying their button prompts in turn.

If my player interacts with something which generates a text box or other modal, I want the button prompt to disappear, but to return when the text box or modal is closed.

Any advice on how to go about achieving this?

I've done it in the past in different engines, but I have always been unhappy with how convoluted my method was. I'd like to hear how others might tackle this. Given how common this kind of thing is in games, I'm surprised I haven't found a good tutorial on it yet.

You can be as general or as specific as you'd like in your answer.

\$\endgroup\$

1 Answer 1

2
\$\begingroup\$

I'd divide this problem into three parts: the Interactable, the Interactor, and your InteractionUI.

Your Interactable objects all have:

  • A script that exposes public methods to get the interactable state (eg. enabled/disabled), appropriate interaction prompt description(s), and to trigger the action of the object.

    This could all be one shared script (exposing an OnInteract Unity event you can wire up in the inspector), subtypes of a common base Interactive, or unrelated components implementing an IInteractive interface if you need very divergent behaviours

  • A trigger collider marking the interaction range (so it can be differently sized/shaped/positioned for each interaction, as appropriate).

    Put this collider in an Interactables physics layer so it's easy to filter to where you need it.

Your Interactor script within your player character object maintains a list of Interactables in range, and an index or reference to the one currently selected/prioritized.

  • Inside OnTriggerEnter/Exit2D methods, it adds and removes interactables to maintain this list. If the list goes from empty to non-empty, it can fire an InteractionAvailable event.

    If the selected interaction goes out of range, it can fire an InteractionUnavailable event, or cycle to the next Interactable and send an InteractionChanged event.

  • Each frame, you can check that the selected Interactable is still in a usable state, and optionally rank its range/priority/centeredness in view against the others in the list to decide whether to swap which interaction is presented, firing InteractionChanged events as needed.

    If auto-selecting between interactables, ensure you give a bias toward the currently selected one — this adds some hysteresis so that your selection doesn't flicker unpredictably.

Lastly, your InteractionUI subscribes to events from the Interactor, and uses that information to show, update, or hide the interaction prompt. It can also communicate with your other UI to hide the prompt when appropriate.

  • When you're in a UI state that allows interacting with the prompt, the InteractionUI can forward the interaction button input to the Interactor's currently selected Interactable.

    You can cache the previous selection on InteractionChanged to make it available a fraction of a second longer while the visible UI prompt transitions, if you find it's too easy to accidentally trigger the wrong one during a swap.

  • When more than one interaction is available, the UI can display prompts and forward inputs to the Interactor to cycle between them.

Above I haven't strictly separated the view & controller roles of the UI layer, but you can if it suits your approach to UI and input. The main point is separating out the model role into the Interactor component, which helps keep your interaction management logic from getting too entangled with UI presentation or input control state, and makes it easier if you ever want to introduce multiplayer or switching between multiple characters.

So, summarizing:

  • you have an object that knows how it wants to be interacted with

  • you have an Interactor that manages the set of interactions currently available to a given actor in the scene

  • you have a UI controller that handles navigating and acting on the available interactions for the player's (current) actor

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .