There are lots of different ways to solve this.
Here's what I'd setup:
- Create a new scene inheriting from Area2D and call it
Interactable
.
- Set the Area2D's collision layer and mask to a new, unused one (you can go to your project settings and call it "Interaction", if you want).
- Attach a script to the Area2D.
- Connect the Area2D's signals for entering/leaving areas to new functions and add a new variable (e.g.
partner
) that's set set to the entering body (or null
upon leaving).
- Add a new signal
on_interact
and a simple function _interact()
emitting said signal.
- Add a new function (e.g.
interact()
) and within it check to see if partner
has a valid value. If it has one, call partner._interact()
.
Now you're done:
- Add an instance of your
Interactable
scene to your player and any NPC or interactable object (like signs). Make it so they can touch each other when close enough. You'd typically make the player one as big as the player and the others so they include the area where an interaction should be possible.
- In your NPC connect the
on_interaction
signal to load/display your dialog and you should be set, unless I missed something typing this out.
Bonus Thing 1: I remember seeing a very similar approach (without signals I think) made by DevDuck, explained in this DevLog for "Dauphin". The interesting part starts around 6:15.
Bonus Thing 2: Rather than using the variable partner
as a simple 1:1 connection, you could also use an array to collect multiple interactables, then in interact()
iterate over all of them.
Bonus Thing 3: The design above should make it really easy to emit additional signals whenever an area is entered/left you can listen to, to connect stuff like visible interaction prompts (like "Press E to ").