Calling set_process(true) in my script doesn't restart _process() being called

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

I’m trying to code a Textbox in my game. The textbox plays out it’s text over time, character by character. When it’s finished showing it’s text it calls set_process(false) to stop it’s processing.

Now I want the textbox to show different text, so I reset it’s state, set_process(true) and… nothing happens. For some reason _process isn’t called again. There is no errors/debug messages and I don’t know why processing doesn’t resume.

The code in question:

# first file, an Area2D that triggers the textbox when
# the player walks into it
extends Area2D

func _ready():
    var err = connect("body_entered", self, "start_script")
    if err != OK:
        print(err)

func start_script(_body):
    var textbox_scene = load("res://scenes/entities/textbox/textbox.tscn")
    var textbox = textbox_scene.instance()
    textbox.top_line_text = "Hello?"

    add_child(textbox)

    yield(textbox, "text_shown")

    print("This is reached")

    # this resets the state, sets the two lines of text
    # and calls set_process(true)
    textbox.show_text("Why is this never shown?", "")

    print("This is also reached")

    yield(textbox, "text_shown")

    print("This is not reached")

    textbox.queue_free()

and

# textbox.gd
func show_text(top: String, bottom: String):
    ...
    set_process(true)
    print("Set Process should be true")

func _process(delta):
    print("Processing")
    ...

This all outputs the text:

Processing
... # processing is printed multiple times
Processing
This is reached
Set Process should be true
This is also reached
# this is where I expect more processing to be printed, but it
# never is. indicating to me _process is never called again

I think the problem isn’t in the code you shared. Something else might be happening. It could be that the line doing set_process(false) (which you didn’t post) is being executed after you set the next text to execute, due to the order things actually happen when emitting the text_shown signal.

I made a test project doing something similar and it worked fine.

Zylann | 2020-03-09 19:04

I’m not sure what else could be happening. It’s a pretty simple project at the moment. The only thing I can imagine is that start_script is a coroutine, but I don’t know why that would mess with it at all.

jedesjardins | 2020-03-09 19:10

Here is an example of what I mean:
In the test project I just made, my process function in the text box looks like this:

func _process(delta):
	if _char_index <= len(_text):
		text = _text.left(_char_index)
		_char_index += 1
	else:
		set_process(false)
		emit_signal("text_shown")

This one works. But if I invert the order of emit_signal:

		emit_signal("text_shown")
		set_process(false)

This no longer works and the text box never plays the second text. And that happens because show_text() (which is supposed to bring back process to true) is called from inside the emit_signal, and when the signal has been handled, it resumes to the next line, which is… set_process(false). So it never plays the text.

You may check your project if you haven’t done the same mistake. You may otherwise share more of it.

Zylann | 2020-03-09 19:14

Well shoot, that was it. I didn’t realize the code that yields to the signal is called synchronously after the signal is emitted.
Thank you!
(I don’t know if you get positive karma or anything for having the answer. If you submit an official answer I will mark it as such, however)

jedesjardins | 2020-03-09 19:17

Added as answer :wink:

Zylann | 2020-03-09 19:24

:bust_in_silhouette: Reply From: Zylann

Shot in the dark turned out to hit :slight_smile:

I think you have a problem in your text box _process function.
In the test project I just made, my process function in the text box looks like this:

func _process(delta):
	if _char_index <= len(_text):
		text = _text.left(_char_index)
		_char_index += 1
	else:
		set_process(false)
		emit_signal("text_shown")

This one works. But if I invert the order of emit_signal:

		emit_signal("text_shown")
		set_process(false)

This no longer works and the text box never plays the second text. And that happens because show_text() (which is supposed to bring back process to true) is called from inside the emit_signal, and when the signal has been handled, it resumes to the next line, which is… set_process(false). So it never plays the text.