Hello,

So I have been trying to figure this out for over 6 months (not joking) and watched almost every tutorial. For some reason a ton of tutorials are found for the 2D side of Godot but almost none for the 3D side which makes this process even more frustrating to deal with. I have been almost on every site there is for the current problem I have at the moment.

I really want to make a 2D scene for the Dialogue Box and a Dialogue System which uses a .JSON file (this one I was able to do myself).

Lastly I want this to be applied to the 3D side of Godot.

I know that you can use the "Area" node to detect if a Kinematic Body entered or left. So I would want to use that as some kind of trigger signal I sadly don't have the skills yet to really figure out what is the fastest or best way.

for example: Kinematic Body (the Player) enters the Area of another KinematicBody (the NPC) -> Signal sent to code to make the Interaction Button (the Enter Key) available -> Once Pressed Talking with NPC starts -> continue pressing "Interaction Button" to skip to the next tab -> Eventually Closing

I am not really advanced with coding so I wanted it to be simple for now and build later on it when I got more experience.

If you need any files that can help, for example : Character Sprites, .JSON file or any already made coding I would love to send it to you.

Kind regards,

It’s been a bit since I’ve worked with dialog systems, but for a trigger, something like this should make it where when the player is in the Area node and they press a button, a signal is sent (untested):

extends Area
var _is_player_in_area = false
# We will use the node name to detect if the node is the
# player or not. You may need to change this depending
# on how your game is setup and/or project requirements
export (String) var player_node_name = “Player”

# Custom signal (I’m not sure if the syntax here is correct...)
signal on_player_interact
# track if the player has interacted so we do not restart
# the interaction while the dialog is going
var _has_player_interacted = false

func _ready():
	connect(“body_entered”, self, “_on_body_entered”)
	connect(“body_exited”, self, “_on_body_exited”)

func _process():
	if _is_player_in_area == true and _has_player_interacted == false:
		# In this example, the interact key is E, though you
		# probably want to change this with an action
		if Input.is_key_down(KEY_E):
			emit_signal(“on_player_interact”)
			_has_player_interacted = true
			# Interact prompt UI should, probably, be disabled here.

func _on_body_entered(other):
	if other.name == player_node_name:
		_is_player_in_area = true
		_has_player_interacted = false
		# If you have UI to show (like “press E to interact”)
		# then you could enable it here.

func _on_body_exited(other):
	if _is_player_in_area == true:
		if other.name == player_node_name:
			_is_player_in_area = false
			_has_player_interacted = false

Hopefully this helps!

@TwistedTwigleg I am glad that you want to help :)

The code does contain an error when testing but it doesn't crash (or stops the testing or how you would like to call it)

The error is as follows:

Error calling method from signal 'body_entered': 'Area(NPC.gd)::_on_NPC_body_entered': Method not found. <C source> core object.cpp:1238 @ emit_signal()

I think what happens is that the code doesn't know what to do when the 'Player' is in the area and presses the interact key.

It might be that because during a test run I pressed 5 times on the 'E' in the area and the error is shown 5 times.

Do you know which line of code the error is being generated by? It could be that the issue is generated due to the Area not knowing what to do when the player is present in the Area, but I'm not sure why that would cause it to output an error.

Based on the error report, I'd guess it is the line containing emit_signal(“on_player_interact”), but looking at the documentation, it appears that is the correct way to emit a custom signal.

@TwistedTwigleg after looking for more issues or at least see where it comes from I tried to reset my layers (every character (only 2 of them) had a different layer for defining interactable and player) and when testing I saw a new error line

this one being that the code doesn't know what to do when the KinematicBody(player) exited the area

for both the issues, when entered and exited, there is no specific red line where I could've made a typo or wrong there was a wrong method.

so only in the "errors" tab is the whole thing seen

So the 3 "seperate" errors seen by me now are:

Error calling method from signal 'body_entered': 'Area(NPC.gd)::on_body_entered': Method not found.

Error calling method from signal 'body_entered':'Area(NPC.gd)::_on_NPC_body_entered': Method not found.

Error calling method from signal 'body_exited':'Area(NPC.gd)::on_body_exited': Method not found

Based on the errors, it looks like it cannot find the functions for the on_body_entered and on_body_exited signals. My guess is that the syntax in the connect functions in _ready is wrong. I'll try to make a quick prototype later today and see if I can figure out why the code is not working.

Okay, I tested the code and made a few changes, since I had some syntax errors. Here is the code from the test/prototype project:

extends Area
var _is_player_in_area = false
# We will use the node name to detect if the node is the
# player or not. You may need to change this depending
# on how your game is setup and/or project requirements
export (String) var player_node_name = "Player"
# Custom signal (I’m not sure if the syntax here is correct...)
signal on_player_interact
# track if the player has interacted so we do not restart
# the interaction while the dialog is going
var _has_player_interacted = false

func _ready():
	connect("body_entered", self, "_on_body_entered")
	connect("body_exited", self, "_on_body_exited")
	
	connect("on_player_interact", self, "_test_function");

func _process(delta):
	if _is_player_in_area == true and _has_player_interacted == false:
		# In this example, the interact key is E, though you
		# probably want to change this with an action
		if Input.is_key_pressed(KEY_E):
			emit_signal("on_player_interact")
			_has_player_interacted = true
			# Interact prompt UI should, probably, be disabled here.

func _on_body_entered(other):
	if other.name == player_node_name:
		_is_player_in_area = true
		_has_player_interacted = false
		# If you have UI to show (like “press E to interact”)
		# then you could enable it here.

func _on_body_exited(other):
	if _is_player_in_area == true:
		if other.name == player_node_name:
			_is_player_in_area = false
			_has_player_interacted = false

func _test_function():
	print ("Interacted!");

The issue I was having was that the Godot didn't like " and I used the wrong name for the Input function. I was not able to reproduce the signal issue, it just worked, though to be fair I just connected the signal to simple function within the same script.

(Sorry about the delay! I thought I could get to it yesterday, but it didn't work out)

@TwistedTwigleg I will show my Hierarchy , because for some reason I still have an error but I dont know why but when I typed yours over I had the error and I also when I Copy Pasted it I had the error)

Cuz my problem could be because of a wrong tree.

The error that I keep getting is btw: Error calling method from signal 'body_entered': 'Area(NPC.gd)::_on_NPC_body_entered': Method not found.

What if you try to delete and recreate the signal on the NPC node? I wonder if it isn't the NPC node name, from the error it seem like you might have created the signal on it before you renamed the node?

@Megalomaniak I am going to look into that cuz it is strange that it does work on @TwistedTwigleg his side Thanks for the tip

@TwistedTwigleg How does your Project look like ( hierarchy and connections) because in the script there are 3 connections made

I want to know which one is connected to which. Those give me the yellow warning saying they aren't used which they should be.

I also found out that when E is pressed no print is made which says 'interact'

I want to know this because I want to be sure that I am following the right steps and no longer cause a bit of confusion. ?

Here is what my scene looks like:

The reason it looks a little strange is because I slapped it into another prototype project for testing purposes. If you want, I can make a fresh project and upload it here to the forums if that would help.

@TwistedTwigleg Again I have tried to rewrite the code, Copy pasted it and also tried theorising why yours works and mine doesnt and I am really stun by this but I really don't know :/

so yeah maybe it is better if you could send a fresh project

I would be really happy if the trigger system is able to work cuz that gives a huge step into making a dialog system work =)

Try recreating the node structure with the Area node named as Area and the script, thus, named as Area.gd

@Megalomaniak @TwistedTwigleg I will try to test all of this tomorrow

(depends on when you are reading it, so from this post?)

Thanks btw?

@TwistedTwigleg sorry for the long wait had a lot to do yesterday but after a lot of digging through your code and also trying to copy it (word for word in code and build up) I have managed to make this work!

I am really happy that the trigger system finally worked this will make the step to connecting for conversations much easier.

because now I only need to look how to make is an action func like when pressing E start .JSON file instead of the label text. =)

No worries on the delay. I'm glad the sample project was useful! :D

When I get everything done (before some time) I will make a video about this so other don't have to bumb into this so hard like I did for the past 6 months ?

Hi again, I have found a code which controls the writting and control of the text. I have changed it around a bit so I can control the page changing with the SPACEBAR

extends RichTextLabel

var dialog = ["Hey! My name is Benjamin.", "Welcome to the TestStet world"]
var page = 0

func _ready():
	set_bbcode(dialog[page])
	set_visible_characters(0)
	set_process_input(true)

func _input(event):
	if event is InputEventKey and event.get_scancode() == KEY_SPACE && event.is_pressed():
		if get_visible_characters() > get_total_character_count():
			if page < dialog.size()-1:
				page += 1
				set_bbcode(dialog[page])
				set_visible_characters(0)>

func _on_Timer_timeout():
	set_visible_characters(get_visible_characters()+1)

This from a tutorial coding from HeartBeast - Youtube

The label that we have now can be changed into a RichTextLabel which also uses bbcode

I was wondering where (or how) I can place the load function. At first I thought that I could use the

var dialog line to place a load method but I wasn't able to make it happen

My .JSON file uses id's to detect which lines of dialog are going to be loaded

If the file is needed I will be able to sent it