How to trigger a function if the player's overlapping an Area2D and a key is pressed?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By exuin

I’m trying to get a dialogue window to pop up if the player moves in front of a certain Area2D and then presses the “space” key. How do I do this? I tried using the “body_entered” signal from Area2D but that should only trigger when the player first enters the area.

:bust_in_silhouette: Reply From: njamster

Honestly, I think it’s easier to attach the Area2D to the player and then do this:

func _physics_process(delta):
	if Input.is_action_just_pressed("ui_accept"):
		for body in $Area2D.get_overlapping_bodies():
			if body.has_method("interact"):
				body.interact()

That’s assuming all NPCs the player can interact with in your game are either of type StaticBody, KinematicBody or RigidBody and have an interact-method defined in their scripts, where you would then spawn the dialogue window, etc.

Please note: If there are multiple bodies in the area the player could interact with, he will interact with all of them, in the order returned by get_overlapping_bodies(). If you don’t want this, simply return after the first interaction.


If you still want to do your way, you could add a new variable to the player script:

var npcs_in_reach = []

Then connect the “body_entered” and “body_exited”-signals for each of your objects:

func _on_Area2D_body_entered(body):
	if body.name == "Player":
		body.npcs_in_reach.append(self.get_path())

func _on_Area2D_body_exited(body):
	if body.name == "Player":
		body.npcs_in_reach.erase(self.get_path())

Here I use the players name to make sure, that the body is really the player and not something else. Depending on your game, that might not be the best way to ensure this, but it’s easy to grasp, so I’ll use this here for the sake of simplicity.

Now your player script would look something like this:

func _physics_process(delta):
	if Input.is_action_just_pressed("ui_accept"):
		var npc_path = npcs_in_reach.front()
		if npc_path: get_node(npc_path).interact()

Again, this is assuming your NPCs have an interact-method defined in their scripts. Also the interaction will just trigger for one NPC. Even if there are multiple in reach, it will always choose the one who entered the Area2D first (and is still in it).

Thanks, I did that first method and it worked.

exuin | 2020-02-14 00:32

:bust_in_silhouette: Reply From: Asthmar

Here is a simple solution

Create a var , let’s call it “player_in”

Make a body _enter signal, under the body enter function set the player_in var to true.

Now make a body _exit signal, under the body_exit function set the player_in var to false

Lastly under your func process delta put if body_in == true : #Check for your input

I would also suggest having your player in a group and only check for a body in that group so things like npc wont trigger the dialouge also.