Dialogue line wont continue on click URGENT

godot 4.3

first time using gdscript and godot, gamejam ends this friday, im lost

extends Control

@onready var colleague = %Colleague
@onready var astral = %Astral
@onready var astro = %Astro
@onready var mimi = %Mimi
@onready var rin = %Rin
@onready var woolie = %Woolie

@onready var heart = $Heart
@onready var dialogue = %Dialogue

var dialogue_start: bool = false
var clicked: bool = false

var colleague_dialogue_lines = [
	"Hey, you must be the new hire!",
	"I can already tell we are going to be besties, or cesties? Like colleagues and besties!",
	".....",
	"no?",
	"Ok let's get you started",
	"We have four drink recipes, make sure to remember them",
	"To make a coffee you need coffeebeans, Milk and sugar",
	"To make a tea you need matcha and sugar",
	"To make a matcha latte you need matcha and milk",
	"and finally for a hot chocolate you need chocolate, milk and sugar",
	"When you have selected the correct ingredients you press on the drink machine to brew the drink",
	"Now with that being said",
]  # Colleague's unique dialogue lines

func _ready() -> void:
	button_blink()
	dialogue.connect("gui_input", Callable(self, "_on_dialogue_clicked"))

func _process(_float) -> void:
	if colleague.visible:
		colleague_dialogue()

func colleague_dialogue():
	if colleague.visible == true:
		# Start the dialogue when the colleague is visible
		await get_tree().create_timer(1.0).timeout
		self.visible = true
		show_dialogue(colleague_dialogue_lines)  # Call function to show dialogue lines

# Function to display dialogue line by line
func show_dialogue(lines: Array) -> void:
	if dialogue_start:
		return
	dialogue_start = true

	var typing_speed = 0.05  # Speed of typing 
	dialogue.text = ""  # Clear previous text

	for line: String in lines:
		dialogue.text = ""
		var chars = line.split("", true)  # Split the line into individual characters for typing effect
		for c in chars:
			dialogue.text += c  # Add one character at a time
			await get_tree().create_timer(typing_speed).timeout
		await wait_for_input()

	dialogue_start = false

func wait_for_input() -> void:
	clicked = false  # Reset flag
	while not clicked:
		await get_tree().process_frame  # Wait for dialogue click

func _on_dialogue_clicked(event):
	if event is InputEventMouseButton and event.pressed:
		clicked = true

# Function to make the button blink
func button_blink():  
	var tween = create_tween().set_loops()
	tween.tween_property(heart, "visible", false, 0.8)
	tween.tween_property(heart, "visible", true, 0.8)

Can you explain what you expect to happen versus what really happens?

this code could be split into at least 3 scripts and obejcts.

you are using await in process which halts execution, but not using await with a method with await inside, so it runs in parallel and then multiple times.

Is this thing working at all?

1 - add await to process:

func _process(_float) -> void:
	if colleague.visible:
		await colleague_dialogue()

2 - add await to show_dialoge:

func colleague_dialogue():
	if colleague.visible == true:
		# Start the dialogue when the colleague is visible
		await get_tree().create_timer(1.0).timeout
		self.visible = true
		await show_dialogue(colleague_dialogue_lines)  # Call function to show dialogu

3 - process is being interrupted by await. input should come from a different node than this.

await wait_for_input() #wrong

await click_node.clicked_on#create a node with a custom signal that is triggered when there's a mouse click

after testing some things now the dialogue just speeds very fast without stopping. I want the dialogue to stop and then continue when clicking on every single line of dialogue.

Tested out with your fixes and it doesn’t solve the problem. There is no halt between the sentences and the dialogue just rambles on without stop.

the problem was it didn’t continue. now it does continue I imagine?

let’s look at code execution again

1 - it’s in process #next time trigger a function from a signal, you are using awaits
2 - pause of 1.0 seconds
3 - show
4 -


if dialogue_start:
	return
dialogue_start = true

I don’t see what this does. it feels useless.
you are already halting execution of code with awaits.


for line: String in lines:
	dialogue.text = ""
	var chars = line.split("", true)  # Split the line into individual characters for typing effect
	for c in chars:
		dialogue.text += c  # Add one character at a time
		await get_tree().create_timer(typing_speed).timeout
	await wait_for_input()#replace this with mynode.clicked_on custom signal

5 - for loop line
6 - reset dialog text
7 - for loop char
8 - wait 0.05 seconds
9 - wait_for_input.
at this point I recommended you create a separate node to handle input and emit a signal that would be awaited here instead.
10 - continue for loop line
11 - process again, next frame

it should work and the week point would be waiting for input.
the node for handling input would look like this:
could be a button and use the pressed signal, or just use a Control with gui_input.


signal clicked_on
func _ready():
	gui_input.connect(_on_input_event)

func _on_input_event(event):
	if event is InputEventMouseButton and event.pressed:
		clicked_on.emit()
1 Like

I don’t see what this does. it feels useless.
you are already halting execution of code with awaits.

I don’t know either, i’m just following tutorials

it should work and the week point would be waiting for input.
the node for handling input would look like this:
could be a button and use the pressed signal, or just use a Control with gui_input.

all these solutions do not work either, now you can’t click, the dialogue doesn’t continue and it completely bounces around and glitches out :sob:

Here’s what I would recommend,

# Use a signal for next dialogues
signal next_dialogue

func _ready() -> void:
	button_blink()

	# use Godot 4.x connection style
	dialogue.gui_input.connect(_on_dialogue_clicked)

func _process(_float) -> void:
	if colleague.visible:
		colleague_dialogue()
		# you only want to call show_dialogue once.
		# stop _process from calling show dialogue every frame
		set_process(false)

func colleague_dialogue():
	# already checked in _process
	#if colleague.visible == true:

	await get_tree().create_timer(1.0).timeout
	self.visible = true
	show_dialogue(colleague_dialogue_lines)


func show_dialogue(lines: Array) -> void:
	if dialogue_start:
		return
	dialogue_start = true
	dialogue.text = ""

	for line: String in lines:

		# use RichText/Labels visible characters property instead of string slicing
		dialogue.text = line
		var text_tween: Tween = dialogue.create_tween()
		text_tween.tween_property(dialogue, "visible_ratio", 1.0, 2.0).from(0.0)

		# Await a signal
		await next_dialogue

	dialogue_start = false


# Make use of your input directly instead of a infinite while loop
#func wait_for_input() -> void:
	#clicked = false
	#while not clicked:
		#await get_tree().process_frame

func _on_dialogue_clicked(event):
	if event is InputEventMouseButton and event.pressed:
		# Emit the signal directly
		next_dialogue.emit()

I’m sorry you couldn’t finish in time :worried:

the sad part is this is not that difficult, but some of the choices made this look more complex than it really is. there are too many functions calling other functions and everything is in a single script.

I’ll take another look.

func _process(_float) -> void:
	if colleague.visible:
		colleague_dialogue()

func colleague_dialogue():
	if colleague.visible == true:

case in point, this is redundant. this tests for colleague visible twice, but in different ways.


self.visible = true

more redundancy, we have checked twice that this is visible but making it visible again.

this cancels the function that we are calling every frame if dialogue is true. probably done so because whoever coded this didn’t know how to properly use awaits.

more redundancy, we are clearing text twice.

yes, I see why.
there are no guards to stop the text after the cycle is completed.

do this: move the code in process to ready. that should fix it because it will only run once.
to trigger it otherwise you can call a function from a signal or by pressing a button (use an input function)

func _ready() -> void:
	button_blink()
	dialogue.connect("gui_input", Callable(self, "_on_dialogue_clicked"))
	colleague_dialogue()#that's all
func _input():
	if event.is_action_pressed("ui_accept"):
		colleague_dialogue()

I made a quick project that works:

extends Control

@onready var terminal: RichTextLabel = $TabContainer/MarginContainer/terminal

var type_speed : float = 0.01

func cout(messages : Array) -> void:
	terminal.text = ""
	for i : String in messages:
		for j in i.split(""):
			await get_tree().create_timer(type_speed).timeout
			terminal.text += j
		await terminal.advance_text
		terminal.text = ""
	toggle_1 = false

var toggle_1 : bool = false
#WE START HERE, WHEN SPACE IS PRESSED
func _input(event: InputEvent) -> void:
	if not toggle_1:
		if event.is_action_pressed("ui_accept"):
			cout(messages)
			toggle_1 = true

when we press on the label the text advances:


extends RichTextLabel

signal advance_text

func _ready() -> void:
	gui_input.connect(_on_gui_event)

func _on_gui_event(event : InputEvent) -> void:
	if event is InputEventMouseButton and event.is_pressed():
		print("advance text")
		advance_text.emit()