How to make on area entered into a conditional statement?

Godot Version

4.6

Question

Hello!!! So im trying to make it so that you can only interact with something if you enter the area it is in. THis isnt really an extension problem, i know im working with the dialogue manager here but i know the problems my code :3

So, i tried a lot of things, i tried making the unhandled_input into a conditional statement, then the area3d. I tried a few other things too but nothings worked so far, so what am i doing wrong?

heres the code:

extends StaticBody3D #a charecter i wanna interact with



var dialogue_resource = load ("res://DFD.dialogue")



func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("interact"):
		DialogueManager.show_dialogue_balloon(dialogue_resource, "start1")

Make an Area3D that is a child of this body. Then use Area3D::overlaps_body() to test if the player is inside that area. If it is - show the dialogue.

Okay, so i got this:



var player = %DialogueInteraction
var dialogue_resource = load ("res://DFD.dialogue")



func _unhandled_input(event: InputEvent) -> void:
	if Area3D.overlaps_body("player"):
		if event.is_action_pressed("interact"):
			DialogueManager.show_dialogue_balloon(dialogue_resource, "start1")

but it gave me the error “Error at (10, 29): Invalid argument for “overlaps_body()” function: argument 1 should be “Node” but is “String”.”

The argument to overlaps_body() needs to be a reference to player’s character body node.

1 Like

okay, i did that, and then it said i needed to make this an instance. I definitely made some stupid mistakes after that. I thought instance meant a scene, and since it worked that way before, i converted the area i wanted to interact with the other area3d in a new scene and parented it to the player. I then did this:

extends StaticBody3D


@onready var player = "res://Scenes/area_3d.tscn" #area parented to player to interact, didnt bother to rename
@onready var dialogue_resource = load ("res://DFD.dialogue")
@onready var actionable = "res://Scenes/actionable.tscn" #the area3d parented to other characters to talk


func _unhandled_input(event: InputEvent) -> void:
	if player.overlaps_body(actionable):
		if event.is_action_pressed("interact"):
			DialogueManager.show_dialogue_balloon(dialogue_resource, "start1")

and it gave me the error E 0:00:03:177 _unhandled_input: Invalid call. Nonexistent function ‘overlaps_body’ in base ‘String’.

Try using the collision detection of the area to get the player, instead of always having a reference to the player, which is somewhat difficult to get; for example your @onready var player and actionable are not references to nodes, instead they are string paths to files, which aren’t useful in this context.

This is a very common pattern of detecting all body overlaps, and filtering out the ones you want

extends StaticBody3D

var player: Player = null # we do not know who the player is yet

func _on_body_entered(body: Node3D) -> void:
	if body is Player:
		player = body # we found the player

func _on_body_exited(body: Node3D) -> void:
	if body == player:
		player = null # player left the area, forget about them

func _unhandled_input(event: InputEvent) -> void:
	if player != null: # only if we know of the player
		if event.is_action_pressed("interact"):
			DialogueManager.show_dialogue_balloon(dialogue_resource, "start1")
1 Like

okay so now i have this:

extends StaticBody3D

var player: Player = null
var dialogue_resource = load ("res://DFD.dialogue")


func _on_actionable_body_entered(body: Node3D) -> void:
	if body is Player:
		player = body
		print("body entered")


func _on_actionable_body_exited(body: Node3D) -> void:
	if body == player:
		player = null

but its not detecting the area is entered, it wont print what i told it to print.

You could tweak the print to let us know if it detects anything and what that anything might be

func _on_actionable_body_entered(body: Node3D) -> void:
	print("Something entered: ", body)
	if body is Player:
		player = body
		print("player entered; yay!")

It could be that the signal is incorrectly connected, or that your player you are trying to detect is not of class_name Player

oh, i was being a little dumb haha. it was on the wrong collision layer :,D

1 Like

Not the point of this thread, but is there any way i can disable and enable some controls when i press e? (e is interact)

It’s best to use some sort of variable as a condition for if statements, similar to how the sample uses player != null to allow interactions. If there is more state to consider such as dialogue currently running then you can use a variable that keeps track of that. Seems like dialouge manager 3 doesn’t have a built in variable for that, but you can track it via signals DialogueManager.dialogue_started and DialogueManager.dialogue_ended

Thank you so much <333333

Im just going to put this here in case anyone is looking for it later:

to stop your player from moving during the dialogue, you put this code into your player script:

func _physics_process(delta: float) -> void:
    if DialogueManager.dialogue_started:
		set_process(false)
	if DialogueManager.dialogue_ended:
		set_process(true)
	move_and_slide()
1 Like

wait a second, its still not working again. its still moving my charecter when dialogue is running (the first test i was stuck in a collision shape i guess)

Signals do not work on if statements, when used as part of an if the signal will always and immediately evaluate to true, so it’s not useful like this.

You must connect functions to the signals, you could do this on _ready for your player

func _ready() -> void:
    DialogueManager.dialogue_started.connect(_on_dialogue_started)
    DialogueManager.dialogue_ended.connect(_on_dialogue_ended)

func _on_dialogue_started() -> void:
    set_process(false)

func _on_dialogue_ended() -> void:
    set_process(true)

okay, and i feel like this is a stupid quiestion, but where do i actually connect the dialogue? i dont want to have to do this for every line of dialogue i type :,D but when i copied the code it still didnt freeze the player, i feel as though im simply just missing something im sorry

set_process only stops the _process function, if overriden, from running. If your player moves only inside the _process override, then they would freeze. This isn’t common in CharacterBody-type players as they would use _physics_process and may have other forces and functions for movement.

This code should go on your player script, but I’m betting set_process just isn’t the right function for your use case. Rather it may be better to have a new variable for “in_dialogue” that you can add to other movement and interaction if statements.

im sorry i dont think i understand :,D

First you have to know how your player moves. Using set_process(false) probably will not stop movement, you would have to share your player’s script for us to know for sure.

The most common or consistent way to prevent movement would be to use a variable tracking if the player should be “frozen”, then changing the input to zero if set.

var frozen: bool = false

func _physics_process(delta: float) -> void:
    var direction := Input.get_vector("left", "right", "up", "down")
    if frozen:
        direction = Vector2.ZERO

Okay thank you :smiley:

Not sure if this is a godot problem or a dialogue manager problem haha, please correct me, but when I made another dialogue file and attached it (before i attached you code so it couldnt be that), it started saying ‘Invalid call. Nonexistent function ‘get_next_dialogue_line’ in base ‘Nil’.”

Both have this code (Changing the ‘load resource’ and ‘start1’ so that they load seperate dialogue scripts):

extends StaticBody3D

var player: Player = null
var dialogue_resource = load ("res://DFD.dialogue")


var frozen: bool = false

func _physics_process(delta: float) -> void:
	var direction := Input.get_vector("Left", "Right", "Up", "Down")
	if frozen:
		direction = Vector2.ZERO


func _on_actionable_body_entered(body: Node3D) -> void:
	print("something entered")
	if body is Player:
		player = body
		print("body entered")


func _on_actionable_body_exited(body: Node3D) -> void:
	if body == player:
		player = null

func _unhandled_input(event: InputEvent) -> void:
	if player != null: # only if we know of the player
		if event.is_action_pressed("interact"):
			DialogueManager.show_dialogue_balloon(dialogue_resource, "start1")
			frozen = true

Would this be just an easy fix? I keep havign these kinds of problems lol

considering you do not call get_next_dialogue_line in this script I think it must be a part of the dialogue manager, I am not sure what the solution would be.