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
- 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
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 ").