Yield doesn't wait signal

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

Hi guys, i’m currently having a problem with yield. I do have a function “foo” in a main node script that for every node in a list instantiate a custom node and shows a dialogbox (made by me)
Main script:

 var ut: utility = utility.new()
    const dialogPrefab= preload("res://Prefabs/UI/DialogBox.tscn")
    foo(list: Array):
        var position= []
        for e in list:
            ut.instatiateE(position, e, dialogPrefab, $DialogContainer, $EntityContainer)

That’s the utility class script:

extends Node
class_name utility

func instantiateEnemies(position, e, dialog, parentD, parentE):
	var i = randi() % position.size()
	e.translation =  Vector3(position[i].x,position[i].y, position[i].z)
	parentE.add_child(e)
	var dia = dialog.instance()
	dia.init(e.name + " added!")
	dia.set_name("DialogBox")
	diaCont.add_child(dia)
	yield(dia, "okay")
	dia.queue_free()

And that’s my DialogBox script:

extends Control

onready var textPlayer: AnimationPlayer = $NinePatchRect/MarginContainer/Label/TextAnim
signal okay
var text = ""
export var g = false

func init(txt):
	text = txt
	$NinePatchRect/MarginContainer/Label.text = text
	
func _ready():
	textPlayer.play("DisplayText")

func input():
	g = true
	$NinePatchRect/ColorRect/AnimationPlayer.play("Blink")
	
func _process(_delta):
	if Input.is_action_just_released("debug") and g:
		emit_signal("okay")
		g =false

In theory the “for loop” in the main function is interrupted for every enitity in the list until I press(and released) my “debug” action. Now the problem is that in practice it keeps spawning DialogBoxes until the for loop end without waiting my input… How can i handle this situation?

:bust_in_silhouette: Reply From: Inces

The way I see it yield only holds releasing of dialog boxes. Nothing stops them from being created. When “okay” signal is emitted all of dialog boxes are freed. If You want to stop dialog boxes from spawning yieldline must be higher up, before adding dia as a child

:bust_in_silhouette: Reply From: Gluon

The yield doesnt stop all code, it just pauses that function. That means you call instantiateEnemies and it gets to a yield point but your code continues to run and calls the function again so you probably just end up with a lot of paused instantiateEnemies functions.

Your problem is you are not stopping a new instantiateEnemies being called by yielding there, you are just pausing the function before it deletes the previous dialogue box.

Yeah, i figured it out in 3 minutes after the post, thanks anyway :smiley: !

Flipp3rix | 2022-05-29 14:29

:bust_in_silhouette: Reply From: CharlesMerriam

Ah, welcome to the sparsely documented world of yield.

It sparsely documented because it gets complex quickly; some would say it gets weird. It also quickly leads to discussions of signal processing, thread lifetimes, multiprocessing, stack frames, iterators, generators, and coroutines. Then it gets complicated when you add multiple processes.

The most common issues with yield, in my limited experience:

Signal storms: I start to process a signal. In processing a signal, I end up calling something that generates another of the signals I am trying to process. I often ignore the repeated signals. I use a local variable if I want just that instance from restarting (if _guard: return; _guard = true; ....; guard = false; return..). Alternately, a global variable or mutex can be a global guard.

Yield semantics are unclear: Make a scene with just a 2D node and a button named TheButton. Ponder this code and explain why it prints 1, 2, 3, 4 in order:

func do_yield():
     yield($TheButton, "pressed")
     print("4, on the second press")
func _ready():
     print("1")
     yield($TheButton, "pressed")
     print("2, after pressing")
     do_yield()
     print("3, immediately after 2")

Failure to Pause: Modal boxes pause the rest of the game. There is a tutorial, but the short answer is to set the pause mode of your modal to Process and use get_tree().paused = true while dealing with your modal. This suspends the per frame process and physics process used by both your code and most controls, timers, and animators.

That all said, I can see some errors in your code along these lines. I suggest you keep paring down code until it works with small snippets. If this for your debugging, you might cheat and try for a button that just advances the frame.

I look forward to any expansion on the yield semantics, and whatever you learn trying to get past this problem.

FYI, I asked a question on the yield semantics here and got a good response.

CharlesMerriam | 2022-06-02 10:03