I need help with this simple dialog system: (Yes im noob)

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

Hello! So ive made this code to help me interact with objects:

if get_node("RayCast2D").is_colliding():
		var object = get_node("RayCast2D").get_collider()
		if object.is_in_group("Interactebles"): 
			if Input.is_action_pressed('ui_accept'):
				print("Greetings!")
	if get_node("RayCast2D2").is_colliding():
		var object = get_node("RayCast2D2").get_collider()
		if object.is_in_group("Interactebles"): 
			if Input.is_action_pressed('ui_accept'):
				print("Greetings!")

I have two raycasts because i need my player to be able to interact with an object from both sides.
Now, i need help with actually triggering the dialogue. I coded a dialog box: Its a very simple system using a polygon2D and a RitchTextLabel. But now, how can i get it to pop up on screen when the interaction is triggered, and hide it when it’s done?
Also, is there a way to make it so diferent objects have diferent text? For example, if I have a red brick, the text should say: “Its a red brick” and if I have a blue one, “it’s a blue brick.”?

You can assemble your dialog box as you want in a separate scene and preload it.
It would be something like this:

onready var pop_up=preload("res://PopUp.tscn")
var dialog=[]
        
        
if detector.is_colliding():
    var object = detector.get_collider() 
    if Input.is_action_just_pressed('ui_accept'):
        var p=pop_up.instance()
        p.get_node("TextLabel").text="Hello" + str(object.name)
        # + str(object.color) etc etc.
        p.position=object.position+Vector2(0,-30)
        if(dialog.size() > 0):
    	    p.position=dialog.back().position+Vector2(30,0)
        add_child(p)
        dialog.append(p)
    			
if(Input.is_action_just_pressed("ui_cancel") and dialog.size() != 0):
    dialog.pop_back().queue_free()	

This is very basic, as I use str () to combine variables with text, but you can use format string for more options (see the doc).
The position is established according to the previous pop_up but this you would have to adapt to your scene. And be careful with the array especially when they point to node references, look at the documentation on them.
This I tried very fast may have errors or is not what you need. In any case I wait for your response to see what you think

estebanmolca | 2019-12-24 16:31

Hello! This seems legit, but i dont quite understand it.
Am i suposed to put this code in the kinematic body or the poligon 2D?
I’m guessing kinematic body.
Also I find some of the lines hard to understand:

 p.get_node("TextLabel").text="Hello" + str(object.name)
.position=object.position+Vector2(0,-30)
        if(dialog.size() > 0):
            p.position=dialog.back().position+Vector2(30,0)
        add_child(p)
        dialog.append(p)

I would be extremly thankfull if you would help me understand

Anastasia | 2019-12-26 13:27

You can put this code where you need it and where there is a raycast as a child (in my example I refer to it as a ‘detector’). Then you set another scene apart for the dialog box and save it, in my case, it’s a Node2d with a Label and a ColorRect as children (you can use RichTextLabel). The idea is to instantiate this scene as many times as necessary, but in order to later eliminate them I use an array to save each new instance.

1- Create a temporary variable and instantiate the dialog box:
var p = pop_up.instance ()

2-Access the text property of the Label node (which is child of the dialog box and in my case it is called TextLabel) and I assign it a string and use the native function str () to convert a variable to string and concatenate with the operator + (You can use any valid variable):
p.get_node ("TextLabel"). text = "Hello" + str (object.name)

3-Access the position property of the dialog box (node2d is the parent) and assign the same position of the object that detected the raycast plus about -30 pixels on the Y axis: p.position = object.position + Vector2 ( 0, -30)

4-If the array has a size greater than 0 it means that there is already another dialog box in the scene, so, I use the position of the last dialog box in the scene plus about 30 px on the x-axis. (You can access the last object that has an array with my_array.back ()):
if (dialog.size ()> 0): p.position = dialog.back (). position + Vector2 (30,0)

5-add the instance of the dialog box as child of the current scene:
add_child (p)

6-Use the array to save that reference, since when creating a new var p, the previous reference is lost:
dialog.append (p)

7- outside the if statement of the raycast, I delete the last position of the array (the last dialog box created), if the ESC key is pressed and if the array has elements. Unlike back () that returns the last position of the array, pop_back () first returns and then deletes the last element in the array. Then I can use queue_free () to delete the reference (The last dialog box created):
if(Input.is_action_just_pressed("ui_cancel") and dialog.size() != 0): dialog.pop_back().queue_free()

Any questions, ask me and sorry if my English is bad.

estebanmolca | 2019-12-27 04:29

Thank you! But what if i have the text scripted allready?
extends RichTextLabel

var dialog = ["...", "Huh?" , "Where am I?", "...", "Who am I?", "Ow...", "My head hurts..."]
var page = 0

func _ready():
	set_bbcode(dialog[page])
	set_visible_characters(0)
	set_process_input(true)
 
func _input(event):
	if event is InputEventMouseButton:
		if get_visible_characters() > get_total_character_count():
			if page < dialog.size()-1:
				page += 1
				set_bbcode(dialog[page])
				set_visible_characters(0)
		if page == 6:
			if get_visible_characters() > get_total_character_count():
				hide()




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

like this. do i keep it this way or change it?

Anastasia | 2019-12-27 12:00

Assuming that the script you show me would be in the separate scene that we are going to instantiate would look something like this:

var p = RichTextLabel.instance ()
p.text= p.dialog[1]
or:
p.set_bbcode(dialog[p.page])
(I don’t know the functions of RichTextLabel)

Although I don’t know very well what you really want, do you know the game that looks like what you want to implement?

estebanmolca | 2019-12-27 14:45

Yes my dialog box is in a diferent scene.
Yes! Undertale and Hollow Knight are the ones on my mind right now, alrough I do not aim to branch my dialog. I am trying to keep it as basic as posibile
Also when im trying to run it something seems to be wrong with var p=pop_up.instance(). it tells me “Invalid call. Nonexistent function “instance” in “GDScriptNativeClass””

Anastasia | 2019-12-28 08:46

onready var pop_up=preload("res://PopUp.tscn")
Do you have this line at the beginning, before the _ready () function?
In the preload function you have to put the name of the scene you have saved with the dialog box. Although while you are writing it you get the options to choose it.

I’m going to watch some video of those games, then I’ll tell you

estebanmolca | 2019-12-28 11:18

I saw the games, it is different from what I imagined, you do not need an array to reference since they never show more than one at a time, they show one behind the other. Is this correct? The most complicated thing, I think, is to make the text go away showing gradually, but as a string you can treat it as an array of letters I think I know how to do something similar controlling with a variable time, let me try it and then I show you.

estebanmolca | 2019-12-28 11:33

The code from the RichTextLabel creates the typing effect and allows me to put multiple pages. You should try to use it yourself to see what it does.
Also now i have the same error at “var p = RichTextLabel.instance()”
Thank you, I’ll be waiting

Anastasia | 2019-12-29 09:10

:bust_in_silhouette: Reply From: zen3001

every node has a hide() and show() method, except canvaslayer.
get the dialogbox node(what ever it is) and do the the following

DialogBoxNode.show()

if you still didn’t get it, can you please share a screenshot of your scene tree?

well yeah but that dosent help a lot…how would i hide it after it finished? I cant hide the text but cant manage the same with the polygon
Besides i dont think this method would work for multiple objects
thank you anyways

Anastasia | 2019-12-24 13:17

get waht ever node the polygon is and use the hide function that should do it

zen3001 | 2019-12-25 17:27