Noobie having trouble with custom printing function

Godot Version

v4.2.2.stable.official [15073afe3] (copied directly from Godot)

Question

I am trying to write a game that takes place in front of all places, a terminal screen, so naturally, I need a custom printing function to act as a thin “API” for the terminal. Along with printing to the screen, I have added a customizable delay between each character printed to the “terminal”, if a section of the game needs less or more effect. Here is my printing function for reference:

func print_to_terminal(input: String, omit_new_line_char: bool) -> void:
	omit_new_line = omit_new_line_char
	string_queue = input.split("")
	index = 0
	charTimer.start()
	pass

func _on_char_timer_timeout():
	if index < string_queue.size():
		if text.ends_with(cursor_char) == true:
			text = text.erase(text.length() - 1, 1)
		text += string_queue[index]
		index += 1
		$charTimer.start()
	else:
		if self.omit_new_line == false:
			if text.ends_with(cursor_char) == true:
				text = text.erase(text.length() - 1, 1)
			text += "\n> "
		$charTimer.stop()
	pass

the erasing of “cursor_char” was because of a “_” that would periodically be appended and erased at regular intervals to act as a flashing cursor, and it was to ensure it didn’t find it’s way into the output.

There is an issue with this function though. If I have three in succession, like this:

print_to_terminal("test 1", false)
print_to_terminal("test 2", false)
print_to_terminal("test 3", false)

It will skip the first three, and immediately execute the final one, ignoring the previous two.

Trying to use “await” at the start of each of them, and trying to fiddle around with emitting signals, had no effect, if they even worked at all.

I thought it was an issue with non-sequential execution with a timer, but I can’t say for sure. Any idea how to stop this behaviour?

There’s nothing in your print_to_terminal that takes time, so all three functions will be run (sequentially) in the same frame, meaning you only see the effects of the last function call.

To fix this, emit a signal after you finished printing all chars:

signal finished_printing()

func _on_char_timer_timeout():
	if index < string_queue.size():
		# ...
	else:
		# ...
		$charTimer.stop()
		emit_signal("finishing_printing")

and then wait until that signal gets emitted before calling the next function:

print_to_terminal("test 1", false)
await(finishing_printing)
print_to_terminal("test 2", false)
await(finishing_printing)
print_to_terminal("test 3", false)

You could also move that waiting statement into your print_to_terminal function:

func print_to_terminal(input: String, omit_new_line_char: bool) -> void:
	omit_new_line = omit_new_line_char
	string_queue = input.split("")
	index = 0
	charTimer.start()
	await(finishing_printing)

Note however, that the function will (preliminarily) return once it reaches that await statement, so in order to still wait on the outside until the function actually has 100% finished, you’d need to use another await statement, like this:

await print_to_terminal("test 1", false)
await print_to_terminal("test 2", false)
await print_to_terminal("test 3", false)

PS: Also note that both Label and RichtTextLabel both come with a property called visible_characters, which could probably simplify your code quite a bit.

1 Like