+1 vote

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?

Godot version 3.4.4 stable
in Engine by (21 points)

3 Answers

+1 vote
Best answer

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.

by (1,685 points)
selected by

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

+1 vote

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

by (7,309 points)
+1 vote

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.

by (327 points)

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

Welcome to Godot Engine Q&A, where you can ask questions and receive answers from other members of the community.

Please make sure to read Frequently asked questions and How to use this Q&A? before posting your first questions.
Social login is currently unavailable. If you've previously logged in with a Facebook or GitHub account, use the I forgot my password link in the login box to set a password for your account. If you still can't access your account, send an email to [email protected] with your username.